//
// Vis5DVerticalSystem.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.data.vis5d;

import visad.CommonUnit;
import visad.CoordinateSystem;
import visad.ErrorEstimate;
import visad.Gridded1DSet;
import visad.IdentityCoordinateSystem;
import visad.Linear1DSet;
import visad.RealTupleType;
import visad.RealType;
import visad.SampledSet;
import visad.Set;
import visad.Unit;
import visad.VisADException;
import visad.data.units.ParseException;
import visad.data.units.Parser;

/**
 * Class for encapsulating the Vis5D vertical system as VisAD
 * MathTypes and Data objects
 */
public class Vis5DVerticalSystem
{
  private static int counter = 0;

  /** Unit used for the vertical system */
  Unit  vert_unit = null;
  /** Sampled Set of values */
  SampledSet vertSet;
  /** RealType of the vertical system parameter */
  RealType vert_type;
  /** CoordinateSystem to transform to Reference values */
  CoordinateSystem vert_cs;
  /** Reference RealTupleType for the CoordinateSystem */
  RealTupleType reference;
  
  /**
   * Construct the VisAD MathTypes and Data objects that relate
   * to the Vis5D vertical system parameters.
   * @param vert_sys  Vis5D vertical System 
   * @param n_levels  number of levels in vert_args
   * @param vert_args array of vertical level values
   * @throws VisADException  unknown vert_sys or problem creating VisAD
   *                         objects.
   * @see visad.data.vis5d.V5DStruct#VertArgs for explanation of vertical
   *      coordinates.
   */
  public Vis5DVerticalSystem( int vert_sys,
                              int n_levels,
                              double[] vert_args)
         throws VisADException
  {

    switch ( vert_sys )
    {
      case (0):
        vert_unit = CommonUnit.promiscuous;
        vert_type = makeRealType("Height", vert_unit);
        reference = new RealTupleType(RealType.Generic);
        vert_cs = new IdentityCoordinateSystem(reference);
        break;
      case (1):
      case (2):
        try {
          vert_unit = Parser.parse("km");
        }
        catch (ParseException e) {
        }
        vert_type = makeRealType("Height", vert_unit);
        reference = new RealTupleType(RealType.Altitude);
        vert_cs = new IdentityCoordinateSystem(reference);
        break;
      case (3):
        try {
          vert_unit = Parser.parse("mbar");
        }
        catch (ParseException e) {
        }
        vert_type = makeRealType("Pressure", vert_unit);
        reference = new RealTupleType(RealType.Altitude);
        vert_cs = new Vis5DVerticalCoordinateSystem();
        break;
      default:
        throw new VisADException("vert_sys unknown");
    }

    switch ( vert_sys )
    {
      case (0):
      case (1):
        double first = vert_args[0];
        double last = first + vert_args[1]*(n_levels-1);
        vertSet = new Linear1DSet(vert_type, first, last, n_levels,
                           (CoordinateSystem) null, new Unit[] {vert_unit}, 
                           (ErrorEstimate[]) null);
        break;
      case (2):  // Altitude in km - non-linear
        double[][] values = new double[1][n_levels];
        System.arraycopy(vert_args, 0, values[0], 0, n_levels);
        vertSet =
          new Gridded1DSet(vert_type, Set.doubleToFloat(values), n_levels,
                           (CoordinateSystem) null, new Unit[] {vert_unit}, 
                           (ErrorEstimate[]) null);
        break;
      case (3):  // heights of pressure surfaces in km - non-linear
        double[][] pressures = new double[1][n_levels];
        System.arraycopy(vert_args, 0, pressures[0], 0, n_levels);
        for (int i = 0; i < n_levels; i++) pressures[0][i] *=1000; // km->m
        pressures = vert_cs.fromReference(pressures); // convert to pressures
        vertSet =
          new Gridded1DSet(vert_type, Set.doubleToFloat(pressures), n_levels,
                           (CoordinateSystem) null, new Unit[] {vert_unit}, 
                           (ErrorEstimate[]) null);
        break;
      default:
         throw new VisADException("vert_sys unknown");
    }
  }

  /** create a unique RealType for the specified name and unit */
  private RealType makeRealType(String name, Unit unit) 
      throws VisADException {
    RealType rt = null;
    rt = RealType.getRealType(name, unit);
    if (rt == null) {
      rt = RealType.getRealType(name+"_"+counter++, unit);
      if (rt == null) {
        throw new VisADException(
          "Unable to create a unique RealType named " + name + 
          " with unit " + unit);
      }
    }
    return rt;
  }

  /**
   * Vis5DVerticalCoordinateSystem is the VisAD class for coordinate
   * systems for transforming pressure in millibars to Altitude
   * in m.  It uses the standard Vis5D climate formulas:
   * 
   *         P = 1012.5 * e^( H / -7.2 )        (^ denotes exponentiation)
   * 
   *         H = -7.2 * Ln( P / 1012.5 )        (Ln denotes natural log)
   * 
* for the transformations (in this case H is in km). *

*/ public static class Vis5DVerticalCoordinateSystem extends CoordinateSystem { /** Default scale value for logarithmic vertical coordinate system */ private static final double DEFAULT_LOG_SCALE = 1012.5; /** Default exponent value for logarithmic vertical coordinate system */ private static final double DEFAULT_LOG_EXP = -7.2; private static Unit[] csUnits; static { try { csUnits = new Unit[] {Parser.parse("mbar")}; } catch (ParseException pe) {;} // can't happen? } /** * Construct a new vertical transformation system */ public Vis5DVerticalCoordinateSystem() throws VisADException { super( new RealTupleType(RealType.Altitude), csUnits ); } /** * Converts pressures in millibars to altitude in meters. * @param pressures array of pressures * @return array of corresponding altitudes * @throws VisADException illegal input */ public double[][] toReference(double[][] pressures) throws VisADException { int length = pressures[0].length; double[][] alts = new double[1][length]; for (int kk = 0; kk < length; kk++) { alts[0][kk] = pressureToAltitude(pressures[0][kk]); } return alts; } /** * Converts altitudes in m to pressure in millibars. * @param alts array of altitudes * @return array of corresponding pressures * @throws VisADException illegal input */ public double[][] fromReference(double[][] alts) throws VisADException { int length = alts[0].length; double[][] pressures = new double[1][length]; for (int kk = 0; kk < length; kk++) { pressures[0][kk] = altitudeToPressure(alts[0][kk]); } return pressures; } /** * Converts pressures in millibars to altitude in meters. * @param pressures array of pressures * @return array of corresponding altitudes * @throws VisADException illegal input */ public float[][] toReference(float[][] pressures) throws VisADException { int length = pressures[0].length; float[][] alts = new float[1][length]; for (int kk = 0; kk < length; kk++) { alts[0][kk] = (float) pressureToAltitude(pressures[0][kk]); } return alts; } /** * Converts altitudes in m to pressure in millibars. * @param alts array of altitudes * @return array of corresponding pressures * @throws VisADException illegal input */ public float[][] fromReference(float[][] alts) throws VisADException { int length = alts[0].length; float[][] pressures = new float[1][length]; for (int kk = 0; kk < length; kk++) { pressures[0][kk] = (float) altitudeToPressure(alts[0][kk]); } return pressures; } /** * Checks the equality of o against this coordinate system * @param o object in question * @return true if o is a Vis5DVerticalCoordinateSystem */ public boolean equals(Object o) { return (o instanceof Vis5DVerticalCoordinateSystem); } /** * Converts an altitude value in meters to a pressure value in * millibars. It uses the standard Vis5D climate formula: *

     *         P = 1012.5 * e^( H / -7.2 )     (^ denotes exponentiation)
     *
     * (H is in km in this formula, but input value is meters)
     * 
* @param alt value to convert * @return corresponding pressure value */ public static double altitudeToPressure(double alt) { return (DEFAULT_LOG_SCALE * Math.exp((alt/1000.) / DEFAULT_LOG_EXP)); } /** * Converts a pressure value in millibars to an altitude in * meters. It uses the standard Vis5D climate formula: *
     *         H = -7.2 * Ln( P / 1012.5 )        (Ln denotes natural log)
     *
     * (H is in km in this formula, but returned value is meters)
     * 
* @param pressure value to convert * @return corresponding altitude value */ public static double pressureToAltitude(double pressure) { return (DEFAULT_LOG_EXP * Math.log( pressure / DEFAULT_LOG_SCALE)) * 1000.; } } }

Ads help maintain this website.