Пример #1
0
  /**
   * Set the sounding in the table
   *
   * @param sounding the sounding
   * @throws RemoteException Java RMI problem
   * @throws VisADException problem dissecting data
   */
  private void setupTable(Field sounding) throws VisADException, RemoteException {

    Set domain = sounding.getDomainSet();
    CoordinateSystem cs = domain.getCoordinateSystem();

    numDomainCols = domain.getDimension();
    if (cs != null) {
      numDomainCols++;
    }
    RealType[] rangeComps = ((FunctionType) sounding.getType()).getRealComponents();
    numRangeCols = rangeComps.length;
    columnNames = new String[numDomainCols + numRangeCols];

    SetType t = (SetType) domain.getType();
    Unit[] units = domain.getSetUnits();
    RealTupleType rtt = t.getDomain();
    RealType[] comps = rtt.getRealComponents();
    columnNames[0] = makeColumnName(comps[0], units[0]);
    if ((cs != null)) {
      RealTupleType refType = cs.getReference();
      RealType[] refComps = refType.getRealComponents();
      Unit[] refUnits = cs.getReferenceUnits();
      columnNames[1] = makeColumnName(refComps[0], refUnits[0]);
    }

    // set for default
    for (int i = 0; i < rangeComps.length; i++) {
      columnNames[numDomainCols + i] =
          makeColumnName(rangeComps[i], rangeComps[i].getDefaultUnit());
    }
    // wind
    if (rangeComps.length > 2) {
      csUnits = new Unit[] {rangeComps[2].getDefaultUnit(), rangeComps[3].getDefaultUnit()};
      haveUV =
          (Unit.canConvert(csUnits[0], CommonUnit.meterPerSecond)
              && Unit.canConvert(csUnits[1], CommonUnit.meterPerSecond));
      if (haveUV) {
        windTransform =
            new InverseCoordinateSystem(
                new RealTupleType(Speed.getRealType(), Direction.getRealType()),
                new PolarHorizontalWind.PolarCoordinateSystem(
                    new RealTupleType(rangeComps[2], rangeComps[3]),
                    CommonUnit.meterPerSecond,
                    CommonUnit.degree));
      } else {
        windTransform = new PolarHorizontalWind.PolarCoordinateSystem(csUnits[0], csUnits[1]);
      }
    }
    if (model == null) {
      model = new SoundingTableModel();
      sorter = new TableSorter(model);
      JTableHeader header = getTableHeader();
      header.setToolTipText("Click to sort");
      sorter.setTableHeader(getTableHeader());
      setModel(sorter);
      setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
      setPreferredScrollableViewportSize(new Dimension(400, 200));
      getTableHeader().setReorderingAllowed(false);
    }
  }
Пример #2
0
  /**
   * Set the sounding in the table
   *
   * @param sounding the sounding
   * @throws RemoteException Java RMI problem
   * @throws VisADException problem dissecting data
   */
  private void setSounding(Field sounding) throws VisADException, RemoteException {
    domainData = null;

    // domain values
    Set domain = sounding.getDomainSet();
    CoordinateSystem cs = domain.getCoordinateSystem();

    float[][] domSamples = domain.getSamples(false);
    if ((cs != null)) {
      float[][] domFloats = Set.copyFloats(domSamples);
      // Must convert from the default coordinate domain system to
      // the domain coordinate system of the sounding.
      String fromUnit = sounding.getDomainUnits()[0].toString();
      String toUnit = cs.getCoordinateSystemUnits()[0].toString();
      if (!fromUnit.equals(toUnit) && SimpleUnit.isCompatible(fromUnit, toUnit)) {
        float conversionFactor = (float) SimpleUnit.getConversionFactor(fromUnit, toUnit);
        for (int i = 0; i < domFloats.length; i++) {
          for (int j = 0; j < domFloats[i].length; j++) {
            domFloats[i][j] = domFloats[i][j] * conversionFactor;
          }
        }
      }
      float[][] refData = cs.toReference(domFloats);
      domainData = new float[][] {domSamples[0], refData[0]};
    }
    // range values
    RealType[] rangeComps = ((FunctionType) sounding.getType()).getRealComponents();
    rangeData = sounding.getFloats(false);

    // wind
    if (rangeComps.length > 2) {
      transformWinds = (showUAndV && !haveUV) || (!showUAndV && haveUV);
      if (!transformWinds) {
        for (int i = 2; i < 4; i++) {
          columnNames[numDomainCols + i] =
              makeColumnName(rangeComps[i], rangeComps[i].getDefaultUnit());
        }
      } else {
        RealTupleType refType = windTransform.getReference();
        Unit[] refUnits = windTransform.getReferenceUnits();
        for (int i = 0; i < 2; i++) {
          columnNames[numDomainCols + i + 2] =
              makeColumnName((RealType) refType.getComponent(i), refUnits[i]);
        }
        float[][] newVals =
            windTransform.toReference(Set.copyFloats(new float[][] {rangeData[2], rangeData[3]}));
        rangeData[2] = newVals[0];
        rangeData[3] = newVals[1];
      }
    }
    sorter.setTableModel(model);
  }
Пример #3
0
    /**
     * Sets the set of times of all the profiles. The set will contain one or more times as double
     * values, in order, from earliest to latest.
     *
     * @param times The times of all the profiles.
     * @param source
     * @throws VisADException if a VisAD failure occurs.
     * @throws RemoteException if a Java RMI failure occurs.
     */
    public void setTimes(SampledSet times, SoundingDataNode source)
        throws VisADException, RemoteException {

      RealType timeType = (RealType) ((SetType) times.getType()).getDomain().getComponent(0);

      // use a LineDrawing because it's the simplest DisplayableData
      if (timesHolder == null) {
        timesHolder = new LineDrawing("times ref");
      }

      /*
       * Add a data object to the display that has the right
       * time-centers.
       */
      Field dummy =
          new FieldImpl(new FunctionType(timeType, AirTemperatureProfile.instance()), times);

      for (int i = 0, n = times.getLength(); i < n; i++) {
        dummy.setSample(i, AirTemperatureProfile.instance().missingData());
      }

      timesHolder.setData(dummy);
      if (widget == null) {
        if (times.getLength() == 1) {
          DateTime time =
              new DateTime(
                  new Real(
                      timeType, times.indexToDouble(new int[] {0})[0][0], times.getSetUnits()[0]));

          widget = GuiUtils.wrap(new JLabel(time.toString()));
          dataNode.setTime(time);
          setSounding(0);
        } else {
          //
          // Set the animation.
          //
          Animation animation = getInternalAnimation(timeType);
          getSoundingView().setExternalAnimation(animation, getAnimationWidget());
          aeroDisplay.addDisplayable(animation);
          aeroDisplay.addDisplayable(timesHolder);

          Container container = Box.createHorizontalBox();
          // Wrap these components so they don't get stretched in the Y direction
          container.add(GuiUtils.wrap(getAnimationWidget().getContents(false)));
          // container.add(GuiUtils.wrap (animationWidget.getIndicatorComponent()));

          widget = container;
        }
      }
    }
Пример #4
0
 /** evaluate the extract function */
 public static Data extract(visad.Field f, Real r) {
   Data d = null;
   try {
     d = f.extract((int) r.getValue());
   } catch (VisADException exc) {
     if (FormulaVar.DEBUG) exc.printStackTrace();
   } catch (RemoteException exc) {
     if (FormulaVar.DEBUG) exc.printStackTrace();
   }
   return d;
 }
Пример #5
0
  /**
   * Converts grid-relative winds to true (or absolute) winds. The U and V components of true wind
   * are {@link WesterlyWind} and {@link SoutherlyWind}, respectively. If the input {@link
   * visad.Field} is not a time-series, then it must be a {@link visad.FlatField} and it must be
   * compatible with the argument of {@link #cartesianHorizontalWind(FlatField)}. If, however, the
   * the input {@link visad.Field} is a time-series, then its domain must be a temporal {@link
   * visad.Gridded1DSet} or a {@link visad.SingletonSet} and its range values must be compatible
   * with the argument of {@link #cartesianHorizontalWind(FlatField)}.
   *
   * @param rel The grid-relative winds.
   * @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 is not a time-series and is incompatible
   *     with {@link #cartesianHorizontalWind(FlatField)}, or if the input field is a time-series
   *     but its range values are incompatible with {@link #cartesianHorizontalWind(FlatField)}.
   * @throws VisADException if a VisAD failure occurs.
   * @throws RemoteException if a Java RMI failure occurs.
   */
  public static Field cartesianHorizontalWind(Field rel) throws VisADException, RemoteException {

    RealTupleType domType = ((FunctionType) rel.getType()).getDomain();
    Field result = null;
    if (RealType.Time.equalsExceptNameButUnits(domType)
        || RealType.TimeInterval.equalsExceptNameButUnits(domType)) {
      result = timeSeriesCartesianHorizontalWind(rel);
    } else {
      result = cartesianHorizontalWind((FlatField) rel);
    }
    return result;
  }
Пример #6
0
 /** evaluate the bracket function; e.g., A1[5] or A1[A2] */
 public static Data brackets(visad.Field f, Real r) {
   Data value = null;
   try {
     RealType rt = (RealType) r.getType();
     value = f.getSample((int) r.getValue());
   } catch (VisADException exc) {
     if (FormulaVar.DEBUG) exc.printStackTrace();
   } catch (RemoteException exc) {
     if (FormulaVar.DEBUG) exc.printStackTrace();
   }
   return value;
 }
Пример #7
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;
  }
Пример #8
0
  /**
   * 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;
  }
Пример #9
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;
  }
Пример #10
0
  /**
   * Computes the output property. A {@link java.beans.PropertyChangeEvent} is fired for the output
   * property if it differs from the previous value.
   *
   * @throws VisADException if a VisAD failure occurs.
   * @throws RemoteException if a Java RMI exception occurs.
   */
  void clock() throws VisADException, RemoteException {

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

    /* Eliminate non-finite pressures and buoyancies. */
    int n = 0;

    for (int i = 0; i < pressures.length; i++) {
      if ((pressures[i] != pressures[i]) || (buoys[i] != buoys[i])) {
        n++;
      }
    }

    if (n > 0) {
      double[] tmpPres = new double[pressures.length - n];
      float[] tmpBuoy = new float[tmpPres.length];

      n = 0;

      for (int i = 0; i < pressures.length; i++) {
        if ((pressures[i] != pressures[i]) || (buoys[i] != buoys[i])) {
          continue;
        }

        tmpPres[n] = pressures[i];
        tmpBuoy[n] = buoys[i];

        n++;
      }

      pressures = tmpPres;
      buoys = tmpBuoy;
    }

    if (pressures.length <= 1) {
      newLfc = missingLfc;
    } else {
      Unit presUnit = domainSet.getSetUnits()[0];
      boolean ascending = pressures[0] > pressures[1];

      if (!ascending) {

        /*
         * The profile is descending.  Make the temporary value arrays
         * ascending.
         */
        for (int i = 0, j = pressures.length; i < pressures.length / 2; i++) {
          --j;

          double pres = pressures[i];

          pressures[i] = pressures[j];
          pressures[j] = pres;

          float buoy = buoys[i];

          buoys[i] = buoys[j];
          buoys[j] = buoy;
        }
      }

      /*
       * Descend from the top to positive buoyancy.
       */
      int i = buoys.length;

      while ((--i >= 0) && (buoys[i] <= 0)) ;

      if (i < 0) {

        /*
         * There is no positively buoyant region.
         */
        newLfc = missingLfc;
      } else {

        /*
         * Descend to first non-positive buoyant region.
         */
        while ((--i >= 0) && (buoys[i] > 0)) ;

        if (i < 0) {

          /*
           * There is no non-positive buoyant region.
           */
          newLfc = missingLfc;
        } else {

          /*
           * Interpolate the LFC.
           */
          double pressure =
              pressures[i + 1]
                  / Math.exp(
                      buoys[i + 1]
                          * (Math.log(pressures[i] / pressures[i + 1])
                              / (buoys[i] - buoys[i + 1])));

          newLfc = new Real((RealType) missingLfc.getType(), pressure, presUnit);
        }
      }
    }

    synchronized (this) {
      oldLfc = lfc;
      lfc = newLfc;
    }

    firePropertyChange(OUTPUT_PROPERTY_NAME, oldLfc, newLfc);
  }
Пример #11
0
  /**
   * run 'java visad.bom.ImageRendererJ3D len step' to test animation behavior of ImageRendererJ3D
   * renders a loop of len at step ms per frame then updates loop by deleting first time and adding
   * a new last time
   */
  public static void main(String args[]) throws VisADException, RemoteException, IOException {

    int step = 1000;
    int len = 3;
    if (args.length > 0) {
      try {
        len = Integer.parseInt(args[0]);
      } catch (NumberFormatException e) {
        len = 3;
      }
    }
    if (len < 1) len = 1;
    if (args.length > 1) {
      try {
        step = Integer.parseInt(args[1]);
      } catch (NumberFormatException e) {
        step = 1000;
      }
    }
    if (step < 1) step = 1;

    // create a netCDF reader
    Plain plain = new Plain();

    // open a netCDF file containing an image sequence and adapt
    // it to a Field Data object
    Field raw_image_sequence = null;
    try {
      // raw_image_sequence = (Field) plain.open("images256x256.nc");
      raw_image_sequence = (Field) plain.open("images.nc");
    } catch (IOException exc) {
      String s =
          "To run this example, the images.nc file must be "
              + "present in\nthe current directory."
              + "You can obtain this file from:\n"
              + "  ftp://www.ssec.wisc.edu/pub/visad-2.0/images.nc.Z";
      System.out.println(s);
      System.exit(0);
    }

    // just take first half of raw_image_sequence
    FunctionType image_sequence_type = (FunctionType) raw_image_sequence.getType();
    Set raw_set = raw_image_sequence.getDomainSet();
    float[][] raw_times = raw_set.getSamples();
    int raw_len = raw_times[0].length;
    if (raw_len != 4) {
      throw new VisADException("wrong number of images in sequence");
    }
    float raw_span = (4.0f / 3.0f) * (raw_times[0][3] - raw_times[0][0]);

    double[][] times = new double[1][len];
    for (int i = 0; i < len; i++) {
      times[0][i] = raw_times[0][i % raw_len] + raw_span * (i / raw_len);
    }
    Gridded1DDoubleSet set = new Gridded1DDoubleSet(raw_set.getType(), times, len);
    Field image_sequence = new FieldImpl(image_sequence_type, set);
    for (int i = 0; i < len; i++) {
      image_sequence.setSample(i, raw_image_sequence.getSample(i % raw_len));
    }

    // create a DataReference for image sequence
    final DataReference image_ref = new DataReferenceImpl("image");
    image_ref.setData(image_sequence);

    // create a Display using Java3D
    DisplayImpl display = new DisplayImplJ3D("image display");

    // extract the type of image and use
    // it to determine how images are displayed
    FunctionType image_type = (FunctionType) image_sequence_type.getRange();
    RealTupleType domain_type = image_type.getDomain();
    // map image coordinates to display coordinates
    display.addMap(new ScalarMap((RealType) domain_type.getComponent(0), Display.XAxis));
    display.addMap(new ScalarMap((RealType) domain_type.getComponent(1), Display.YAxis));
    // map image brightness values to RGB (default is grey scale)
    display.addMap(new ScalarMap((RealType) image_type.getRange(), Display.RGB));
    RealType hour_type = (RealType) image_sequence_type.getDomain().getComponent(0);
    ScalarMap animation_map = new ScalarMap(hour_type, Display.Animation);
    display.addMap(animation_map);
    AnimationControl animation_control = (AnimationControl) animation_map.getControl();
    animation_control.setStep(step);
    animation_control.setOn(true);

    /*
        // link the Display to image_ref
        ImageRendererJ3D renderer = new ImageRendererJ3D();
        display.addReferences(renderer, image_ref);
        // display.addReference(image_ref);
    */

    // create JFrame (i.e., a window) for display and slider
    JFrame frame = new JFrame("ImageRendererJ3D test");
    frame.addWindowListener(
        new WindowAdapter() {
          public void windowClosing(WindowEvent e) {
            System.exit(0);
          }
        });

    // create JPanel in JFrame
    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
    panel.setAlignmentY(JPanel.TOP_ALIGNMENT);
    panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
    frame.getContentPane().add(panel);

    // add display to JPanel
    panel.add(display.getComponent());

    // set size of JFrame and make it visible
    frame.setSize(500, 500);
    frame.setVisible(true);

    System.out.println("first animation sequence");
    // link the Display to image_ref
    ImageRendererJ3D renderer = new ImageRendererJ3D();
    display.addReferences(renderer, image_ref);
    // display.addReference(image_ref);

    // wait 4 * len seconds
    new Delay(len * 4000);

    // substitute a new image sequence for the old one
    for (int i = 0; i < len; i++) {
      times[0][i] = raw_times[0][(i + 1) % raw_len] + raw_span * ((i + 1) / raw_len);
    }
    set = new Gridded1DDoubleSet(raw_set.getType(), times, len);
    FieldImpl new_image_sequence = new FieldImpl(image_sequence_type, set);
    for (int i = 0; i < len; i++) {
      new_image_sequence.setSample(i, raw_image_sequence.getSample((i + 1) % raw_len));
    }

    System.out.println("second animation sequence");

    // tell renderer to resue frames in its scene graph
    renderer.setReUseFrames(true);
    image_ref.setData(new_image_sequence);
  }