// @todo Make sure units are meters
 public double getElevation(int point)
     throws IOException // optional; units meters;  missing = NaN.
     {
   Array array = null;
   try {
     array = getElevation(this.getPointRange(point));
   } catch (InvalidRangeException e) {
     IllegalArgumentException iae =
         new IllegalArgumentException(
             "Point <"
                 + point
                 + "> not in valid range <0, "
                 + (this.getNumberPoints() - 1)
                 + ">: "
                 + e.getMessage());
     iae.initCause(e);
     throw iae;
   }
   if (array instanceof ArrayDouble) {
     return array.getDouble(array.getIndex());
   } else if (array instanceof ArrayFloat) {
     return array.getFloat(array.getIndex());
   } else {
     throw new IOException(
         "Elevation variable not float or double <" + array.getElementType().toString() + ">.");
   }
 }
 // @todo Make sure units are degrees_east
 public double getLongitude(int point) throws IOException // required, units degrees_east
     {
   Array array = null;
   try {
     array = getLongitude(this.getPointRange(point));
   } catch (InvalidRangeException e) {
     IllegalArgumentException iae =
         new IllegalArgumentException(
             "Point <"
                 + point
                 + "> not in valid range <0, "
                 + (this.getNumberPoints() - 1)
                 + ">: "
                 + e.getMessage());
     iae.initCause(e);
     throw iae;
   }
   if (array instanceof ArrayDouble) {
     return (array.getDouble(array.getIndex()));
   } else if (array instanceof ArrayFloat) {
     return (array.getFloat(array.getIndex()));
   } else {
     throw new IOException(
         "Longitude variable not float or double <" + array.getElementType().toString() + ">.");
   }
 }
 public double getTimeValue(int point) throws IOException {
   Array array = null;
   try {
     array = getTime(this.getPointRange(point));
   } catch (InvalidRangeException e) {
     IllegalArgumentException iae =
         new IllegalArgumentException(
             "Point <"
                 + point
                 + "> not in valid range <0, "
                 + (this.getNumberPoints() - 1)
                 + ">: "
                 + e.getMessage());
     iae.initCause(e);
     throw iae;
   }
   if (array instanceof ArrayDouble) {
     return (array.getDouble(array.getIndex()));
   } else if (array instanceof ArrayFloat) {
     return (array.getFloat(array.getIndex()));
   } else if (array instanceof ArrayInt) {
     return (array.getInt(array.getIndex()));
   } else {
     throw new IOException(
         "Time variable not float, double, or integer <"
             + array.getElementType().toString()
             + ">.");
   }
 }
 public StructureData getData() throws IOException {
   if (sdata != null) return sdata;
   try {
     return (SingleTrajectory.this.getData(point));
   } catch (InvalidRangeException e) {
     throw new IllegalStateException(e.getMessage());
   }
 }
  public void writeRecord(String stnName, Date obsDate, StructureData sdata) throws IOException {
    StationTracker stnTracker = stationMap.get(stnName);
    ProfileTracker proTracker = stnTracker.profileMap.get(obsDate);

    if (proTracker == null) {
      proTracker = new ProfileTracker(profileIndex);
      stnTracker.profileMap.put(obsDate, proTracker);

      stnTracker.link.add(profileIndex);
      stnTracker.lastChild = profileIndex;
      stnTracker.numChildren++;

      try {
        originTime[0] = profileIndex; // 2d index
        timeArray.set(0, dateFormatter.toDateTimeStringISO(obsDate));
        parentArray.set(0, stnTracker.parent_index);
        ncfile.writeStringData(timeName, originTime, timeArray);
        ncfile.write(parentStationIndex, originTime, parentArray);
      } catch (InvalidRangeException e) {
        e.printStackTrace();
        throw new IllegalStateException(e);
      }

      profileIndex++;
    }

    // needs to be wrapped as an ArrayStructure, even though we are only writing one at a time.
    ArrayStructureW sArray = new ArrayStructureW(sdata.getStructureMembers(), new int[] {1});
    sArray.setStructureData(sdata, 0);

    // track the min and max date
    if ((minDate == null) || minDate.after(obsDate)) minDate = obsDate;
    if ((maxDate == null) || maxDate.before(obsDate)) maxDate = obsDate;

    timeArray.set(0, dateFormatter.toDateTimeStringISO(obsDate));
    parentArray.set(0, proTracker.parent_index);

    proTracker.link.add(recno);
    proTracker.lastChild = recno; // not currently used
    proTracker.numChildren++;

    // write the recno record
    origin[0] = recno; // 1d index
    originTime[0] = recno; // 2d index
    try {
      ncfile.write("record", origin, sArray);
      ncfile.write(parentProfileIndex, originTime, parentArray);
    } catch (InvalidRangeException e) {
      e.printStackTrace();
      throw new IllegalStateException(e);
    }

    recno++;
  }
 public Range getFullRange() {
   Range range = null;
   try {
     range = new Range(0, this.getNumberPoints() - 1);
   } catch (InvalidRangeException e) {
     IllegalStateException ise =
         new IllegalStateException(
             "Full trajectory range invalid <0, "
                 + (this.getNumberPoints() - 1)
                 + ">: "
                 + e.getMessage());
     ise.initCause(e);
     throw (ise);
   }
   return range;
 }
 public Array getData(int point, String parameterName) throws IOException {
   try {
     return (getData(this.getPointRange(point), parameterName));
   } catch (InvalidRangeException e) {
     IllegalArgumentException iae =
         new IllegalArgumentException(
             "Point <"
                 + point
                 + "> not in valid range <0, "
                 + (this.getNumberPoints() - 1)
                 + ">: "
                 + e.getMessage());
     iae.initCause(e);
     throw iae;
   }
 }
  private void writeStationData(List<ucar.unidata.geoloc.Station> stnList) throws IOException {
    this.stnList = stnList;
    int nstns = stnList.size();
    stationMap = new HashMap<String, StationTracker>(2 * nstns);
    if (debug) System.out.println("stationMap created");

    // now write the station data
    ArrayDouble.D1 latArray = new ArrayDouble.D1(nstns);
    ArrayDouble.D1 lonArray = new ArrayDouble.D1(nstns);
    ArrayDouble.D1 altArray = new ArrayDouble.D1(nstns);
    ArrayObject.D1 idArray = new ArrayObject.D1(String.class, nstns);
    ArrayObject.D1 descArray = new ArrayObject.D1(String.class, nstns);
    ArrayObject.D1 wmoArray = new ArrayObject.D1(String.class, nstns);

    for (int i = 0; i < stnList.size(); i++) {
      ucar.unidata.geoloc.Station stn = stnList.get(i);
      stationMap.put(stn.getName(), new StationTracker(i));

      latArray.set(i, stn.getLatitude());
      lonArray.set(i, stn.getLongitude());
      if (useAlt) altArray.set(i, stn.getAltitude());

      idArray.set(i, stn.getName());
      descArray.set(i, stn.getDescription());
      if (useWmoId) wmoArray.set(i, stn.getWmoId());
    }

    try {
      ncfile.write(latName, latArray);
      ncfile.write(lonName, lonArray);
      if (useAlt) ncfile.write(altName, altArray);
      ncfile.writeStringData(idName, idArray);
      ncfile.writeStringData(descName, descArray);
      if (useWmoId) ncfile.writeStringData(wmoName, wmoArray);

    } catch (InvalidRangeException e) {
      e.printStackTrace();
      throw new IllegalStateException(e);
    }
  }
  private void writeDataFinish() throws IOException {
    // finish global variables
    ArrayInt.D0 totalArray = new ArrayInt.D0();
    totalArray.set(profileIndex);
    try {
      ncfile.write(numProfilesTotalName, totalArray);
    } catch (InvalidRangeException e) {
      e.printStackTrace();
      throw new IllegalStateException(e);
    }

    // finish the station data
    int nstns = stnList.size();
    ArrayInt.D1 firstProfileArray = new ArrayInt.D1(nstns);
    ArrayInt.D1 numProfileArray = new ArrayInt.D1(nstns);
    ArrayInt.D1 nextProfileArray = new ArrayInt.D1(nprofiles);

    for (int i = 0; i < stnList.size(); i++) {
      ucar.unidata.geoloc.Station stn = stnList.get(i);
      StationTracker tracker = stationMap.get(stn.getName());

      numProfileArray.set(i, tracker.numChildren);

      int first = (tracker.link.size() > 0) ? tracker.link.get(0) : -1;
      firstProfileArray.set(i, first);

      if (tracker.link.size() > 0) {
        // construct forward link
        List<Integer> nextList = tracker.link;
        for (int j = 0; j < nextList.size() - 1; j++) {
          Integer curr = nextList.get(j);
          Integer next = nextList.get(j + 1);
          nextProfileArray.set(curr, next);
        }
        Integer curr = nextList.get(nextList.size() - 1);
        nextProfileArray.set(curr, -1);
      }
    }

    try {
      ncfile.write(firstProfileName, firstProfileArray);
      ncfile.write(numProfilesName, numProfileArray);
      ncfile.write(nextProfileName, nextProfileArray);

    } catch (InvalidRangeException e) {
      e.printStackTrace();
      throw new IllegalStateException(e);
    }

    // finish the profile data
    ArrayInt.D1 nextObsArray = new ArrayInt.D1(recno);
    ArrayInt.D1 firstObsArray = new ArrayInt.D1(nprofiles);
    ArrayInt.D1 numObsArray = new ArrayInt.D1(nprofiles);

    for (int i = 0; i < stnList.size(); i++) {
      ucar.unidata.geoloc.Station stn = stnList.get(i);
      StationTracker stnTracker = stationMap.get(stn.getName());

      Set<Date> dates = stnTracker.profileMap.keySet();
      for (Date date : dates) {
        ProfileTracker proTracker = stnTracker.profileMap.get(date);
        int trackerIndex = proTracker.parent_index;
        numObsArray.set(trackerIndex, proTracker.numChildren);

        int first = (proTracker.link.size() > 0) ? proTracker.link.get(0) : -1;
        firstObsArray.set(trackerIndex, first);

        if (proTracker.link.size() > 0) {
          // construct forward link
          List<Integer> nextList = proTracker.link;
          for (int j = 0; j < nextList.size() - 1; j++) {
            Integer curr = nextList.get(j);
            Integer next = nextList.get(j + 1);
            nextObsArray.set(curr, next);
          }
          Integer curr = nextList.get(nextList.size() - 1);
          nextObsArray.set(curr, -1);
        }
      }
    }

    try {
      ncfile.write(firstObsName, firstObsArray);
      ncfile.write(numObsName, numObsArray);
      ncfile.write(nextObsName, nextObsArray);

    } catch (InvalidRangeException e) {
      e.printStackTrace();
      throw new IllegalStateException(e);
    }

    // finish the obs data

    ncfile.updateAttribute(
        null, new Attribute("time_coverage_start", dateFormatter.toDateTimeStringISO(minDate)));
    ncfile.updateAttribute(
        null, new Attribute("time_coverage_end", dateFormatter.toDateTimeStringISO(maxDate)));
  }