/**
   * @param gridWinds
   * @param grid
   * @return
   * @throws IllegalArgumentException if the grid is irregular or has too few points or has no
   *     {@link visad.CoordinateSystem}, or if the reference of the grid's {@link
   *     visad.CoordinateSystem} doesn't contain {@link visad.RealType.Latitude} and {@link
   *     visad.RealType.Longitude}.
   * @throws VisADException
   */
  private static float[][] trueWind(float[][] gridWinds, SampledSet grid) throws VisADException {

    if (grid instanceof IrregularSet) {
      throw new IllegalArgumentException(grid.toString());
    }

    CoordinateSystem cs = grid.getCoordinateSystem();
    boolean hasCS = (cs != null);

    RealTupleType rtt = (hasCS) ? cs.getReference() : ((SetType) grid.getType()).getDomain();

    int latI = rtt.getIndex(RealType.Latitude);

    if (latI == -1) {
      throw new IllegalArgumentException(rtt.toString());
    }

    int lonI = rtt.getIndex(RealType.Longitude);

    if (lonI == -1) {
      throw new IllegalArgumentException(rtt.toString());
    }

    if (grid.getManifoldDimension() < 2) {
      throw new IllegalArgumentException(grid.toString());
    }

    float[] us = new float[grid.getLength()];
    float[] vs = new float[grid.getLength()];

    Arrays.fill(us, 0);
    Arrays.fill(vs, 0);
    addComponent(grid, gridWinds, cs, 0, latI, lonI, us, vs);
    addComponent(grid, gridWinds, cs, 1, latI, lonI, us, vs);

    return new float[][] {us, vs};
  }
Beispiel #2
0
  /**
   * Sets the input, buoyancy profile.
   *
   * @param buoyProfile The input, buoyancy profile.
   * @throws TypeException if the domain quantity isn't pressure or the range quantity isn't volume
   *     per mass.
   * @throws VisADException if a VisAD failure occurs.
   * @throws RemoteException if a Java RMI failure occurs.
   */
  public void setBuoyancyProfile(Field buoyProfile)
      throws TypeException, VisADException, RemoteException {

    FunctionType funcType = (FunctionType) buoyProfile.getType();
    RealTupleType domainType = funcType.getDomain();

    if (!Pressure.getRealType().equalsExceptNameButUnits(domainType)) {
      throw new TypeException(domainType.toString());
    }

    MathType rangeType = funcType.getRange();

    if (!CapeBean.massicVolume.equalsExceptNameButUnits(rangeType)) {
      throw new TypeException(rangeType.toString());
    }

    this.buoyProfile = buoyProfile;
  }
  /**
   * The returned {@link visad.FlatField} will have NaN-s for those unit vector components that
   * could not be computed.
   *
   * @param grid The spatial grid.
   * @param index The index of the manifold dimension along which to compute the unit vector.
   * @return A field of components of the unit vector for the given manifold dimension.
   * @throws NullPointerException if the grid is <code>null</code>.
   * @throws IllegalArgumentException if the manifold dimension of the grid is less than 2 or if the
   *     grid doesn't contain {@link visad.RealType#Latitude} and {@link visad.RealType#Longitude}.
   * @throws VisADException if a VisAD failure occurs.
   * @throws RemoteException if a Java RMI failure occurs.
   */
  private static FlatField hatFieldNew(Set grid, int index) throws VisADException, RemoteException {

    CoordinateSystem cs = grid.getCoordinateSystem();
    boolean hasCS = cs != null;

    RealTupleType rtt = (hasCS) ? cs.getReference() : ((SetType) grid.getType()).getDomain();

    int latI = rtt.getIndex(RealType.Latitude);

    if (latI == -1) {
      throw new IllegalArgumentException(rtt.toString());
    }

    int lonI = rtt.getIndex(RealType.Longitude);
    if (lonI == -1) {
      throw new IllegalArgumentException(rtt.toString());
    }

    if (grid.getManifoldDimension() < 2) {
      throw new IllegalArgumentException(grid.toString());
    }

    int[][] neighbors = grid.getNeighbors(index);
    LatLonPointImpl refPt = new LatLonPointImpl();
    LatLonPointImpl neiPt = new LatLonPointImpl();
    Bearing bearing = new Bearing();
    float[] hat1 = new float[2];
    float[] hat2 = new float[2];
    float[][] hat = new float[2][grid.getLength()];

    float[][] refCoords = null;
    float[][] neiCoords = null;
    float[][] domainSamples = grid.getSamples(false);

    refCoords = (hasCS) ? cs.toReference(Set.copyFloats(domainSamples)) : domainSamples;
    // If the grid is lat/lon or has an IdentityCoordinateSystem
    // don't do the rotation
    // TODO:  handle rotated lat/lon grids
    if (!hasCS
        || (refCoords == domainSamples)
        || (Arrays.equals(refCoords[latI], domainSamples[latI])
            && Arrays.equals(refCoords[lonI], domainSamples[lonI]))) {
      if (index == 0) {
        Arrays.fill(hat[0], 1);
        Arrays.fill(hat[1], 0);
      } else {
        Arrays.fill(hat[0], 0);
        Arrays.fill(hat[1], 1);
      }
    } else {

      float latBefore, lonBefore, latAfter, lonAfter;
      // int backOffset = (index==0) ? -180 : 0;
      // int foreOffset = (index==0) ? 0 : -180;
      int backOffset = -180;
      int foreOffset = 0;
      for (int i = 0; i < neighbors.length; i++) {
        refPt.set(refCoords[latI][i], refCoords[lonI][i]);
        if ((neighbors[i][0] < 0) || (neighbors[i][0] >= neighbors.length)) {
          latBefore = Float.NaN;
          lonBefore = Float.NaN;
        } else {
          latBefore = refCoords[latI][neighbors[i][0]];
          lonBefore = refCoords[lonI][neighbors[i][0]];
        }
        if ((neighbors[i][1] < 0) || (neighbors[i][1] >= neighbors.length)) {
          latAfter = Float.NaN;
          lonAfter = Float.NaN;
        } else {
          latAfter = refCoords[latI][neighbors[i][1]];
          lonAfter = refCoords[lonI][neighbors[i][1]];
        }

        compute(refPt, neiPt, latBefore, lonBefore, backOffset, bearing, hat1);

        float d1 = (float) bearing.getDistance();

        compute(refPt, neiPt, latAfter, lonAfter, foreOffset, bearing, hat2);

        float d2 = (float) bearing.getDistance();
        boolean bad1 = Double.isNaN(d1);
        boolean bad2 = Double.isNaN(d2);

        if (bad1 && bad2) {
          hat[0][i] = Float.NaN;
          hat[1][i] = Float.NaN;
        } else {
          if (bad1) {
            hat[0][i] = hat2[0];
            hat[1][i] = hat2[1];
          } else if (bad2) {
            hat[0][i] = hat1[0];
            hat[1][i] = hat1[1];
          } else {
            float tot = d1 + d2;
            float c1 = d2 / tot;
            float c2 = d1 / tot;
            float xhat = c1 * hat1[0] + c2 * hat2[0];
            float yhat = c1 * hat1[1] + c2 * hat2[1];
            float mag = (float) Math.sqrt(xhat * xhat + yhat * yhat);

            hat[0][i] = xhat / mag;
            hat[1][i] = yhat / mag;
          }
        }
      }
    }

    FlatField hatField =
        new FlatField(
            new FunctionType(
                ((SetType) grid.getType()).getDomain(),
                new RealTupleType(
                    RealType.getRealType("xHat", CommonUnit.dimensionless),
                    RealType.getRealType("yHat", CommonUnit.dimensionless))),
            grid);

    hatField.setSamples(hat, false);
    return hatField;
  }
  /**
   * Converts a time-series of grid-relative winds to a time-series of true (or absolute) winds. The
   * U and V components of true wind are {@link WesterlyWind} and {@link SoutherlyWind},
   * respectively. The domain of the input {@link visad.Field} must be a temporal {@link
   * visad.Gridded1DSet} or a {@link visad.SingletonSet}. The range values of the input {@link
   * visad.Field} must be {@link visad.FlatField}s. The domains of the range {@link
   * visad.FlatField}s must have a manifold dimension of two or greater and they must have a
   * reference system which contains {@link visad.RealType#Latitude} and {@link
   * visad.RealType#Longitude}. The number of components in the range of the {@link
   * visad.FlatField}s must be two. Both components must have units convertible with {@link
   * #DEFAULT_SPEED_UNIT}. The first and second components are assumed to be the wind components in
   * the direction of increasing first and second manifold dimension indexes, respectively. The
   * domains of the {@link visad.FlatField}s must be equal. The {@link visad.Field} returned by this
   * method has the same domain as the input {@link visad.Field}. The range values of the returned
   * {@link visad.Field} are {@link visad.FlatField}s that have the same domain as the input {@link
   * visad.FlatField}s. The {@link visad.MathType} of the range of the returned {@link
   * visad.FlatField}s will be <code>CartesianHorizontalWind.getEarthVectorType()</code>.
   *
   * @param rel The time-series of grid-relative wind.
   * @return The time-series of true wind corresponding to the input.
   * @throws NullPointerException if <code>rel</code> is <code>null</code>.
   * @throws IllegalArgumentException if the input field doesn't have a time-series domain, or if
   *     the range values aren't {@link visad.FlatField} with the same domain, or if the domain of
   *     the {@link visad.FlatField}s doesn't have a transformation to latitude and longitude, or if
   *     the domain is irregular or has too few points, or if the {@link visad.FlatField}s don't
   *     have two and only two components in their range, or if the default units of the {@link
   *     visad.FlatField}s range aren't equal.
   * @throws VisADException if a VisAD failure occurs.
   * @throws RemoteException if a Java RMI failure occurs.
   * @see CartesianHorizontalWind
   */
  public static Field timeSeriesCartesianHorizontalWind(Field rel)
      throws VisADException, RemoteException {

    FunctionType outerFuncType = (FunctionType) rel.getType();
    RealTupleType outerDomType = outerFuncType.getDomain();

    if (!(RealType.Time.equalsExceptNameButUnits(outerDomType)
        || !RealType.TimeInterval.equalsExceptNameButUnits(outerDomType))) {
      throw new IllegalArgumentException(outerDomType.toString());
    }

    MathType innerFuncType = outerFuncType.getRange();

    if (!(innerFuncType instanceof FunctionType)) {
      throw new IllegalArgumentException(innerFuncType.toString());
    }

    Field innerField = (Field) rel.getSample(0);
    Set innerDom = innerField.getDomainSet();
    if (innerDom instanceof SingletonSet) {
      return rel;
    } else if (innerDom instanceof GriddedSet) {
      int[] lengths = ((GriddedSet) innerDom).getLengths();
      if ((lengths[0] == 1) && (lengths[1] == 1)) {
        return rel;
      }
    }

    // account for null units, assume m/sec
    Unit[] rangeUnits = innerField.getDefaultRangeUnits();
    if ((rangeUnits == null) || (rangeUnits[0] == null) || rangeUnits[0].isDimensionless()) {
      rangeUnits = CartesianHorizontalWind.getEarthVectorType().getDefaultUnits();
    }
    FunctionType innerType =
        new FunctionType(
            ((SetType) innerDom.getType()).getDomain(),
            CartesianHorizontalWind.getEarthVectorType());

    FlatField uvField =
        new FlatField(innerType, innerDom, (CoordinateSystem) null, (Set[]) null, rangeUnits);

    Field result =
        new FieldImpl(new FunctionType(outerDomType, uvField.getType()), rel.getDomainSet());

    // System.out.println("making rHatField");
    Field rHatField = (doNewCode ? hatFieldNew(innerDom, 0) : hatFieldOld(innerDom, 0));
    // System.out.println("making sHatField");
    Field sHatField = (doNewCode ? hatFieldNew(innerDom, 1) : hatFieldOld(innerDom, 1));

    float[][] rHats = rHatField.getFloats(false);
    // ucar.unidata.util.Misc.printArray("rHats[0]", rHats[0]);
    // ucar.unidata.util.Misc.printArray("rHats[1]", rHats[1]);
    // System.out.println("\n");
    float[][] sHats = sHatField.getFloats(false);
    // ucar.unidata.util.Misc.printArray("sHats[0]", sHats[0]);
    // ucar.unidata.util.Misc.printArray("sHats[1]", sHats[1]);
    // System.out.println("\n");
    float[] us = new float[innerDom.getLength()];
    float[] vs = new float[us.length];

    for (int i = 0, n = rel.getLength(); i < n; i++) {
      if (i > 0) {
        innerField = (Field) rel.getSample(i);
        Set dom = innerField.getDomainSet();
        if (!innerDom.equals(dom)) {
          // System.out.println("new domain");
          innerDom = dom;
          rHatField = (doNewCode ? hatFieldNew(innerDom, 0) : hatFieldOld(innerDom, 0));
          sHatField = (doNewCode ? hatFieldNew(innerDom, 1) : hatFieldOld(innerDom, 1));

          rHats = rHatField.getFloats(false);
          sHats = sHatField.getFloats(false);
          /*
          throw new IllegalArgumentException("template="
                  + innerDom.toString() + "; domain="
                  + dom.toString());
          */
        }
        uvField =
            new FlatField(innerType, innerDom, (CoordinateSystem) null, (Set[]) null, rangeUnits);
        us = new float[innerDom.getLength()];
        vs = new float[us.length];
      }

      float[][] rsWinds = innerField.getFloats(false);
      float[] rWinds = rsWinds[0];
      float[] sWinds = rsWinds[1];
      // ucar.unidata.util.Misc.printArray("rWinds", rWinds);
      // System.out.println("\n");
      // ucar.unidata.util.Misc.printArray("sWinds", sWinds);
      // System.out.println("\n");

      for (int j = 0; j < us.length; j++) {
        us[j] = rWinds[j] * rHats[0][j] + sWinds[j] * sHats[0][j];
        vs[j] = rWinds[j] * rHats[1][j] + sWinds[j] * sHats[1][j];
      }
      // ucar.unidata.util.Misc.printArray("us", us);
      // System.out.println("\n");
      // ucar.unidata.util.Misc.printArray("vs", vs);
      // System.out.println("\n");

      uvField.setSamples(new float[][] {us, vs}, false);
      result.setSample(i, uvField, false);
    }

    return result;
  }
Beispiel #5
0
  /**
   * Computes the output Level of Free Convection (LFC) from an (AirPressure -> MassicVolume)
   * buoyancy profile.
   *
   * @param datums The input data in the same order as during construction: <code>datums[0]
   *                                  </code> is the input buoyancy profile.
   * @return The pressure at the LFC of the buoyancy profile.
   * @throws ClassCastException if an input data reference has the wrong type of data object.
   * @throws TypeException if a VisAD data object has the wrong type.
   * @throws VisADException if a VisAD failure occurs.
   * @throws RemoteException if a Java RMI failure occurs.
   * @throws IllegalArgumentException if the profile is not ascending.
   */
  protected Data compute(Data[] datums) throws TypeException, VisADException, RemoteException {

    Field buoyProfile = (Field) datums[0];
    Real lfc = noData; // default return value

    if (buoyProfile != null) {
      FunctionType funcType = (FunctionType) buoyProfile.getType();
      RealTupleType domainType = funcType.getDomain();

      if (!Pressure.getRealType().equalsExceptNameButUnits(domainType)) {
        throw new TypeException(domainType.toString());
      }

      MathType rangeType = funcType.getRange();

      Util.vetType(MassicVolume.getRealType(), buoyProfile);

      Set domainSet = buoyProfile.getDomainSet();
      double[] pressures = domainSet.getDoubles()[0];
      float[] buoys = buoyProfile.getFloats()[0];

      if (pressures.length > 1) {
        int lastI = pressures.length - 1;
        boolean ascending = pressures[0] >= pressures[lastI];

        Unit presUnit = domainSet.getSetUnits()[0];
        int i;

        if (ascending) {
          /*
           * For a level of free convection to exist, the lower
           * buoyancy must be negative.
           */
          for (i = 0; (i < buoys.length) && (buoys[i] >= 0); i++) ;

          /*
           * To find the level of free convection, ascend to
           * positive buoyancy.
           */
          while ((++i < buoys.length) && (buoys[i] <= 0)) ;

          if (i < buoys.length) {
            lfc = interpolatePres(pressures[i], buoys[i], pressures[i - 1], buoys[i - 1], presUnit);
          }
        } else {
          /*
           * For a level of free convection to exist, the lower
           * buoyancy must be negative.
           */
          for (i = lastI; (i >= 0) && (buoys[i] >= 0); i--) ;

          /*
           * To find the level of free convection, ascend to
           * positive buoyancy.
           */
          while ((--i >= 0) && (buoys[i] <= 0)) ;

          if (i >= 0) {
            lfc = interpolatePres(pressures[i], buoys[i], pressures[i + 1], buoys[i + 1], presUnit);
          }
        }
      }
    }

    return lfc;
  }