public Float10TrajectoryObsDataset(NetcdfDataset ncd) throws IOException {
    super(ncd);

    // Get the names of the two coordinate variables and dimensions
    // and grab the variables and dimensions themselves.
    trajDimName = trajDimNameDefault;
    trajVarName = trajVarNameDefault;
    timeDimName = timeDimNameDefault;
    timeVarName = timeVarNameDefault;

    latVarName = latVarNameDefault;
    lonVarName = lonVarNameDefault;
    elevVarName = elevVarNameDefault;

    Variable latVar = ncd.getRootGroup().findVariable(latVarName);
    latVar.addAttribute(new Attribute("units", "degrees_north"));

    Variable lonVar = ncd.getRootGroup().findVariable(lonVarName);
    lonVar.addAttribute(new Attribute("units", "degrees_east"));

    this.setTrajectoryInfo(
        netcdfDataset.getRootGroup().findDimension(trajDimName),
        netcdfDataset.getRootGroup().findVariable(trajVarName),
        netcdfDataset.getRootGroup().findDimension(timeDimName),
        netcdfDataset.getRootGroup().findVariable(timeVarName),
        netcdfDataset.getRootGroup().findVariable(latVarName),
        netcdfDataset.getRootGroup().findVariable(lonVarName),
        netcdfDataset.getRootGroup().findVariable(elevVarName));
  }
 public Array getData(Range range, String parameterName)
     throws IOException, InvalidRangeException {
   Variable variable = ncfile.getRootGroup().findVariable(parameterName);
   int varRank = variable.getRank();
   int[] varShape = variable.getShape();
   List section = new ArrayList(varRank);
   section.add(range);
   for (int i = 1; i < varRank; i++) {
     section.add(new Range(0, varShape[i] - 1));
   }
   Array array = variable.read(section);
   if (array.getShape()[0] == 1) {
     return (array.reduce(0));
   } else {
     return (array);
   }
   // return( array.getShape()[0] == 1 ? array.reduce( 0 ) : array);
 }
 // @todo Make sure units are meters
 public Array getElevation(Range range) throws IOException, InvalidRangeException {
   List section = new ArrayList(1);
   section.add(range);
   Array a = elevVar.read(section);
   if (elevVarUnitsConversionFactor == 1.0) return (a);
   for (IndexIterator it = a.getIndexIterator(); it.hasNext(); ) {
     if (elevVar.getDataType() == DataType.DOUBLE) {
       double val = it.getDoubleNext();
       it.setDoubleCurrent(val * elevVarUnitsConversionFactor);
     } else if (elevVar.getDataType() == DataType.FLOAT) {
       float val = it.getFloatNext();
       it.setFloatCurrent((float) (val * elevVarUnitsConversionFactor));
     } else if (elevVar.getDataType() == DataType.INT) {
       int val = it.getIntNext();
       it.setIntCurrent((int) (val * elevVarUnitsConversionFactor));
     } else if (elevVar.getDataType() == DataType.LONG) {
       long val = it.getLongNext();
       it.setLongCurrent((long) (val * elevVarUnitsConversionFactor));
     } else {
       throw new IllegalStateException(
           "Elevation variable type <"
               + elevVar.getDataType().toString()
               + "> not double, float, int, or long.");
     }
   }
   return (a);
 }
  public static void main(String args[]) throws Exception {
    long start = System.currentTimeMillis();
    Map<String, ucar.unidata.geoloc.Station> staHash =
        new HashMap<String, ucar.unidata.geoloc.Station>();

    String location = "R:/testdata/sounding/netcdf/Upperair_20070401_0000.nc";
    NetcdfDataset ncfile = NetcdfDataset.openDataset(location);
    ncfile.sendIospMessage(NetcdfFile.IOSP_MESSAGE_ADD_RECORD_STRUCTURE);

    // look through record varibles, for those that have "manLevel" dimension
    // make a StructureData object for those
    StructureMembers sm = new StructureMembers("manLevel");
    Dimension manDim = ncfile.findDimension("manLevel");
    Structure record = (Structure) ncfile.findVariable("record");
    List<Variable> allList = record.getVariables();
    List<VariableSimpleIF> varList = new ArrayList<VariableSimpleIF>();
    for (Variable v : allList) {
      if ((v.getRank() == 1) && v.getDimension(0).equals(manDim)) {
        // public VariableDS(NetcdfDataset ds, Group group, Structure parentStructure, String
        // shortName, DataType dataType,
        // String dims, String units, String desc) {
        varList.add(
            new VariableDS(
                ncfile,
                null,
                null,
                v.getShortName(),
                v.getDataType(),
                "",
                v.getUnitsString(),
                v.getDescription()));
        // (String name, String desc, String units, DataType dtype, int []shape)
        sm.addMember(
            v.getShortName(),
            v.getDescription(),
            v.getUnitsString(),
            v.getDataType(),
            new int[0]); // scalar
      }
    }

    ArrayStructureMA manAS = new ArrayStructureMA(sm, new int[] {manDim.getLength()});

    // need the date units
    Variable time = ncfile.findVariable("synTime");
    String timeUnits = ncfile.findAttValueIgnoreCase(time, "units", null);
    timeUnits = StringUtil.remove(timeUnits, '('); // crappy fsl'ism
    timeUnits = StringUtil.remove(timeUnits, ')');
    DateUnit timeUnit = new DateUnit(timeUnits);

    // extract stations
    int nrecs = 0;
    StructureDataIterator iter = record.getStructureIterator();
    while (iter.hasNext()) {
      StructureData sdata = iter.next();
      String name = sdata.getScalarString("staName");
      ucar.unidata.geoloc.Station s = staHash.get(name);
      if (s == null) {
        float lat = sdata.convertScalarFloat("staLat");
        float lon = sdata.convertScalarFloat("staLon");
        float elev = sdata.convertScalarFloat("staElev");
        s = new StationImpl(name, "", lat, lon, elev);
        staHash.put(name, s);
      }
      nrecs++;
    }
    List<ucar.unidata.geoloc.Station> stnList =
        Arrays.asList(staHash.values().toArray(new ucar.unidata.geoloc.Station[staHash.size()]));
    Collections.sort(stnList);

    // create the writer
    WriterProfileObsDataset writer =
        new WriterProfileObsDataset(location + ".out", "rewrite " + location);
    writer.writeHeader(stnList, varList, nrecs, "prMan");

    // extract records
    iter = record.getStructureIterator();
    while (iter.hasNext()) {
      StructureData sdata = iter.next();
      String name = sdata.getScalarString("staName");
      double timeValue = sdata.convertScalarDouble("synTime");
      Date date = timeUnit.makeDate(timeValue);

      // transfer to the ArrayStructure
      List<String> names = sm.getMemberNames();
      for (String mname : names) {
        manAS.setMemberArray(mname, sdata.getArray(mname));
      }

      // each level is weritten as a seperate structure
      int numMand = sdata.getScalarInt("numMand");
      if (numMand >= manDim.getLength()) continue;

      for (int i = 0; i < numMand; i++) {
        StructureData useData = manAS.getStructureData(i);
        writer.writeRecord(name, date, useData);
      }
    }

    writer.finish();

    long took = System.currentTimeMillis() - start;
    System.out.println("That took = " + took);
  }
 // @todo Make sure units are degrees_east
 public Array getLongitude(Range range) throws IOException, InvalidRangeException {
   List section = new ArrayList(1);
   section.add(range);
   return (lonVar.read(section));
 }
  /**
   * Setup needed for all SingleTrajectoryObsDatatypes. Can only be called once.
   *
   * <p>Units of time varible must be udunits time units. Units of latitude variable must be
   * convertible to "degrees_north" by udunits. Units of longitude variable must be convertible to
   * "degrees_east" by udunits. Units of altitude variable must be convertible to "meters" by
   * udunits.
   *
   * @throws IllegalArgumentException if units of time, latitude, longitude, or altitude variables
   *     are not as required.
   * @throws IllegalStateException if this method has already been called.
   */
  public void setTrajectoryInfo(Config trajConfig) throws IOException {
    if (timeDim != null)
      throw new IllegalStateException("The setTrajectoryInfo() method can only be called once.");

    this.trajectoryId = trajConfig.getTrajectoryId();
    this.timeDim = trajConfig.getTimeDim();
    this.timeVar = trajConfig.getTimeVar();
    this.latVar = trajConfig.getLatVar();
    this.lonVar = trajConfig.getLonVar();
    this.elevVar = trajConfig.getElevVar();

    trajectoryNumPoint = this.timeDim.getLength();
    timeVarUnitsString = this.timeVar.findAttribute("units").getStringValue();

    // Check that time, lat, lon, elev units are acceptable.
    if (DateUnit.getStandardDate(timeVarUnitsString) == null) {
      throw new IllegalArgumentException(
          "Units of time variable <" + timeVarUnitsString + "> not a date unit.");
    }
    String latVarUnitsString = this.latVar.findAttribute("units").getStringValue();
    if (!SimpleUnit.isCompatible(latVarUnitsString, "degrees_north")) {
      throw new IllegalArgumentException(
          "Units of lat var <" + latVarUnitsString + "> not compatible with \"degrees_north\".");
    }
    String lonVarUnitsString = this.lonVar.findAttribute("units").getStringValue();
    if (!SimpleUnit.isCompatible(lonVarUnitsString, "degrees_east")) {
      throw new IllegalArgumentException(
          "Units of lon var <" + lonVarUnitsString + "> not compatible with \"degrees_east\".");
    }
    String elevVarUnitsString = this.elevVar.findAttribute("units").getStringValue();
    if (!SimpleUnit.isCompatible(elevVarUnitsString, "meters")) {
      throw new IllegalArgumentException(
          "Units of elev var <" + elevVarUnitsString + "> not compatible with \"meters\".");
    }

    try {
      elevVarUnitsConversionFactor = getMetersConversionFactor(elevVarUnitsString);
    } catch (Exception e) {
      throw new IllegalArgumentException(
          "Exception on getMetersConversionFactor() for the units of elev var <"
              + elevVarUnitsString
              + ">.");
    }

    if (this.ncfile.hasUnlimitedDimension()
        && this.ncfile.getUnlimitedDimension().equals(timeDim)) {
      Object result = this.ncfile.sendIospMessage(NetcdfFile.IOSP_MESSAGE_ADD_RECORD_STRUCTURE);
      if ((result != null) && (Boolean) result)
        this.recordVar = (Structure) this.ncfile.getRootGroup().findVariable("record");
      else this.recordVar = new StructurePseudo(this.ncfile, null, "record", timeDim);
    } else {
      this.recordVar = new StructurePseudo(this.ncfile, null, "record", timeDim);
    }

    // @todo HACK, HACK, HACK - remove once addRecordStructure() deals with ncd attribute changes.
    Variable elevVarInRecVar = this.recordVar.findVariable(this.elevVar.getFullNameEscaped());
    if (!elevVarUnitsString.equals(elevVarInRecVar.findAttribute("units").getStringValue())) {
      elevVarInRecVar.addAttribute(new Attribute("units", elevVarUnitsString));
    }

    trajectoryVarsMap = new HashMap();
    // for ( Iterator it = this.recordVar.getVariables().iterator(); it.hasNext(); )
    for (Iterator it = this.ncfile.getRootGroup().getVariables().iterator(); it.hasNext(); ) {
      Variable curVar = (Variable) it.next();
      if (curVar.getRank() > 0
          && !curVar.equals(this.timeVar)
          && !curVar.equals(this.latVar)
          && !curVar.equals(this.lonVar)
          && !curVar.equals(this.elevVar)
          && (this.recordVar == null ? true : !curVar.equals(this.recordVar))) {
        MyTypedDataVariable typedVar = new MyTypedDataVariable(new VariableDS(null, curVar, true));
        dataVariables.add(typedVar);
        trajectoryVarsMap.put(typedVar.getShortName(), typedVar);
      }
    }

    trajectory =
        new SingleTrajectory(
            this.trajectoryId,
            trajectoryNumPoint,
            this.timeVar,
            timeVarUnitsString,
            this.latVar,
            this.lonVar,
            this.elevVar,
            dataVariables,
            trajectoryVarsMap);

    startDate = trajectory.getTime(0);
    endDate = trajectory.getTime(trajectoryNumPoint - 1);

    ((SingleTrajectory) trajectory).setStartDate(startDate);
    ((SingleTrajectory) trajectory).setEndDate(endDate);
  }
  public static boolean isValidFile(NetcdfDataset ds) {
    // Check that has a time dimension and a trajectory dimension.
    List list = ds.getRootGroup().getDimensions();
    if (list.size() != 2) return (false);
    Dimension d;
    for (int i = 0; i < 2; i++) {
      d = (Dimension) list.get(i);
      if (!d.getShortName().equals(timeDimNameDefault)
          && !d.getShortName().equals(trajDimNameDefault)) return (false);
    }

    // Check that has a trajectory coordinate variable.
    Variable var = ds.getRootGroup().findVariable(trajVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 1) return (false);
    d = (Dimension) list.get(0);
    if (!d.getShortName().equals(trajDimNameDefault)) return (false);

    // Check that has a time coordinate variable with units that are udunits time
    var = ds.getRootGroup().findVariable(timeVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 1) return (false);
    d = (Dimension) list.get(0);
    if (!d.getShortName().equals(timeDimNameDefault)) return (false);
    String units = var.findAttribute("units").getStringValue();
    Date date = DateUnit.getStandardDate("0 " + units);
    if (date == null) return (false);

    // Check for variable latitude(time) with units of "deg".
    var = ds.getRootGroup().findVariable(latVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 2) return (false);
    for (int i = 0; i < 2; i++) {
      d = (Dimension) list.get(i);
      if (!d.getShortName().equals(timeDimNameDefault)
          && !d.getShortName().equals(trajDimNameDefault)) return (false);
    }
    //    units = var.findAttribute( "units").getStringValue();
    //    if ( ! SimpleUnit.isCompatible( units, "degrees_north")) return( false);

    // Check for variable longitude(time) with units of "deg".
    var = ds.getRootGroup().findVariable(lonVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 2) return (false);
    for (int i = 0; i < 2; i++) {
      d = (Dimension) list.get(i);
      if (!d.getShortName().equals(timeDimNameDefault)
          && !d.getShortName().equals(trajDimNameDefault)) return (false);
    }
    //    units = var.findAttribute( "units").getStringValue();
    //    if ( ! SimpleUnit.isCompatible( units, "degrees_east")) return( false);

    // Check for variable altitude(time) with units of "m".
    var = ds.getRootGroup().findVariable(elevVarNameDefault);
    if (var == null) return (false);
    list = var.getDimensions();
    if (list.size() != 2) return (false);
    for (int i = 0; i < 2; i++) {
      d = (Dimension) list.get(i);
      if (!d.getShortName().equals(timeDimNameDefault)
          && !d.getShortName().equals(trajDimNameDefault)) return (false);
    }
    units = var.findAttribute("units").getStringValue();
    if (!SimpleUnit.isCompatible(units, "m")) return (false);

    return (true);
  }