legacy/src/main/java/ucar/nc2/dt/trajectory/MultiTrajectoryObsDataset.java
public void setTrajectoryInfo( Dimension trajDim, Variable trajVar,
                                 Dimension timeDim, Variable timeVar,
                                 Variable latVar, Variable lonVar, Variable elevVar )
          throws IOException
  {
    this.trajDim = trajDim;
    this.trajVar = trajVar;
    this.timeDim = timeDim;
    this.timeVar = timeVar;
    this.latVar = latVar;
    this.lonVar = lonVar;
    this.elevVar = elevVar;

    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.netcdfDataset.hasUnlimitedDimension() && this.netcdfDataset.getUnlimitedDimension().equals( timeDim))
    {
      this.netcdfDataset.sendIospMessage(NetcdfFile.IOSP_MESSAGE_ADD_RECORD_STRUCTURE);
      this.recordVar = (Structure) this.netcdfDataset.getRootGroup().findVariable( "record");
    } else {
      this.recordVar = new StructurePseudo( this.netcdfDataset, null, "record", timeDim);
    }

    // @todo HACK, HACK, HACK - remove once addRecordStructure() deals with ncd attribute changes.
    Variable latVarInRecVar = this.recordVar.findVariable( this.latVar.getFullNameEscaped() );
    Attribute latVarUnitsAtt = latVarInRecVar.findAttribute( "units");
    if ( latVarUnitsAtt != null && !latVarUnitsString.equals( latVarUnitsAtt.getStringValue() ) )
      latVarInRecVar.addAttribute( new Attribute( "units", latVarUnitsString ) );
    Variable lonVarInRecVar = this.recordVar.findVariable( this.lonVar.getFullNameEscaped() );
    Attribute lonVarUnitsAtt = lonVarInRecVar.findAttribute( "units" );
    if ( lonVarUnitsAtt != null && !lonVarUnitsString.equals( lonVarUnitsAtt.getStringValue() ) )
      lonVarInRecVar.addAttribute( new Attribute( "units", lonVarUnitsString ) );
    Variable elevVarInRecVar = this.recordVar.findVariable( this.elevVar.getFullNameEscaped() );
    Attribute elevVarUnitsAtt = elevVarInRecVar.findAttribute( "units" );
    if ( elevVarUnitsAtt != null && !elevVarUnitsString.equals( elevVarUnitsAtt.getStringValue() ) )
      elevVarInRecVar.addAttribute( new Attribute( "units", elevVarUnitsString ) );

    trajectoryVarsMap = new HashMap();
    for ( Iterator it = this.netcdfDataset.getRootGroup().getVariables().iterator(); it.hasNext(); )
    {
      Variable curVar = (Variable) it.next();
      if ( curVar.getRank() >= 2 &&
         //  !curVar.equals( this.trajVar) && // These two are both one dimensional arrays
         //  !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);
      }
    }

    Range startPointRange = null;
    Range endPointRange = null;
    try
    {
      startPointRange = new Range( 0, 0);
      endPointRange = new Range( trajectoryNumPoint-1, trajectoryNumPoint-1);
    }
    catch ( InvalidRangeException e )
    {
      IOException ioe = new IOException( "Start or end point range invalid: " + e.getMessage());
      ioe.initCause( e);
      throw( ioe);
    }
    List section0 = new ArrayList(1);
    List section1 = new ArrayList(1);
    section0.add( startPointRange);
    section1.add( endPointRange);
    Array startTimeArray;
    Array endTimeArray;
    try
    {
      startTimeArray = this.timeVar.read( section0);
      endTimeArray = this.timeVar.read( section1);
    }
    catch ( InvalidRangeException e )
    {
      IOException ioe = new IOException( "Invalid range during read of start or end point: " + e.getMessage());
      ioe.initCause( e);
      throw( ioe);
    }

    String startTimeString;
    String endTimeString;
    if ( this.timeVar.getDataType().equals( DataType.DOUBLE))
    {
      startTimeString = startTimeArray.getDouble( startTimeArray.getIndex() ) + " " + timeVarUnitsString;
      endTimeString = endTimeArray.getDouble( endTimeArray.getIndex() ) + " " + timeVarUnitsString;
    }
    else if ( this.timeVar.getDataType().equals( DataType.FLOAT))
    {
      startTimeString = startTimeArray.getFloat( startTimeArray.getIndex() ) + " " + timeVarUnitsString;
      endTimeString = endTimeArray.getFloat( endTimeArray.getIndex() ) + " " + timeVarUnitsString;
    }
    else if ( this.timeVar.getDataType().equals( DataType.INT ) )
    {
      startTimeString = startTimeArray.getInt( startTimeArray.getIndex() ) + " " + timeVarUnitsString;
      endTimeString = endTimeArray.getInt( endTimeArray.getIndex() ) + " " + timeVarUnitsString;
    }
    else
    {
      String tmpMsg = "Time var <" + this.timeVar.getFullName() + "> is not a double, float, or integer <" + timeVar.getDataType().toString() + ">.";
      //log.error( tmpMsg );
      throw new IllegalArgumentException( tmpMsg);
    }

    startDate = DateUnit.getStandardDate( startTimeString );
    endDate = DateUnit.getStandardDate( endTimeString);

    trajectoryIds = new ArrayList();
    trajectories = new ArrayList();
    trajectoriesMap = new HashMap();
    Array trajArray = this.trajVar.read();
    Index index = trajArray.getIndex();
    for ( int i = 0; i < trajArray.getSize(); i++ )
    {
      String curTrajId;
      if ( this.trajVar.getDataType().equals( DataType.STRING ) )
      {
        curTrajId = (String) trajArray.getObject( index.set( i ) );
      }
      else if ( this.trajVar.getDataType().equals( DataType.DOUBLE ) )
      {
        curTrajId = String.valueOf( trajArray.getDouble( index.set( i ) ) );
      }
      else if ( this.trajVar.getDataType().equals( DataType.FLOAT ) )
      {
        curTrajId = String.valueOf( trajArray.getFloat( index.set( i ) ) );
      }
      else if ( this.trajVar.getDataType().equals( DataType.INT ) )
      {
        curTrajId = String.valueOf( trajArray.getInt( index.set( i ) ) );
      }
      else
      {
        String tmpMsg = "Trajectory var <" + this.trajVar.getFullName() + "> is not a string, double, float, or integer <" + this.trajVar.getDataType().toString() + ">.";
        //log.error( tmpMsg );
        throw new IllegalStateException( tmpMsg );
      }

      MultiTrajectory curTraj = new MultiTrajectory( curTrajId, i, trajectoryNumPoint, startDate, endDate,
                                                     this.trajVar, this.timeVar, timeVarUnitsString,
                                                     this.latVar, this.lonVar, this.elevVar,
                                                     dataVariables, trajectoryVarsMap );
      trajectoryIds.add( curTrajId);
      trajectories.add( curTraj);
      trajectoriesMap.put( curTrajId, curTraj );
    }
  }
public void setTrajectoryInfo( Dimension trajDim, Variable trajVar,
                                 Dimension timeDim, Variable timeVar,
                                 Variable latVar, Variable lonVar, Variable elevVar )
          throws IOException
  {
    this.trajDim = trajDim;
    this.trajVar = trajVar;
    this.timeDim = timeDim;
    this.timeVar = timeVar;
    this.latVar = latVar;
    this.lonVar = lonVar;
    this.elevVar = elevVar;

    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.netcdfDataset.hasUnlimitedDimension() && this.netcdfDataset.getUnlimitedDimension().equals( timeDim))
    {
      this.netcdfDataset.sendIospMessage(NetcdfFile.IOSP_MESSAGE_ADD_RECORD_STRUCTURE);
      this.recordVar = (Structure) this.netcdfDataset.getRootGroup().findVariable( "record");
    } else {
      this.recordVar = new StructurePseudo( this.netcdfDataset, null, "record", timeDim);
    }

    // @todo HACK, HACK, HACK - remove once addRecordStructure() deals with ncd attribute changes.
    Variable latVarInRecVar = this.recordVar.findVariable( this.latVar.getFullNameEscaped() );
    Attribute latVarUnitsAtt = latVarInRecVar.findAttribute( "units");
    if ( latVarUnitsAtt != null && !latVarUnitsString.equals( latVarUnitsAtt.getStringValue() ) )
      latVarInRecVar.addAttribute( new Attribute( "units", latVarUnitsString ) );
    Variable lonVarInRecVar = this.recordVar.findVariable( this.lonVar.getFullNameEscaped() );
    Attribute lonVarUnitsAtt = lonVarInRecVar.findAttribute( "units" );
    if ( lonVarUnitsAtt != null && !lonVarUnitsString.equals( lonVarUnitsAtt.getStringValue() ) )
      lonVarInRecVar.addAttribute( new Attribute( "units", lonVarUnitsString ) );
    Variable elevVarInRecVar = this.recordVar.findVariable( this.elevVar.getFullNameEscaped() );
    Attribute elevVarUnitsAtt = elevVarInRecVar.findAttribute( "units" );
    if ( elevVarUnitsAtt != null && !elevVarUnitsString.equals( elevVarUnitsAtt.getStringValue() ) )
      elevVarInRecVar.addAttribute( new Attribute( "units", elevVarUnitsString ) );

    trajectoryVarsMap = new HashMap();
    for ( Iterator it = this.netcdfDataset.getRootGroup().getVariables().iterator(); it.hasNext(); )
    {
      Variable curVar = (Variable) it.next();
      if ( curVar.getRank() >= 2 &&
         //  !curVar.equals( this.trajVar) && // These two are both one dimensional arrays
         //  !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);
      }
    }

    Range startPointRange = null;
    Range endPointRange = null;
    try
    {
      startPointRange = new Range( 0, 0);
      endPointRange = new Range( trajectoryNumPoint-1, trajectoryNumPoint-1);
    }
    catch ( InvalidRangeException e )
    {
      IOException ioe = new IOException( "Start or end point range invalid: " + e.getMessage());
      ioe.initCause( e);
      throw( ioe);
    }
    List section0 = new ArrayList(1);
    List section1 = new ArrayList(1);
    section0.add( startPointRange);
    section1.add( endPointRange);
    Array startTimeArray;
    Array endTimeArray;
    try
    {
      startTimeArray = this.timeVar.read( section0);
      endTimeArray = this.timeVar.read( section1);
    }
    catch ( InvalidRangeException e )
    {
      IOException ioe = new IOException( "Invalid range during read of start or end point: " + e.getMessage());
      ioe.initCause( e);
      throw( ioe);
    }

    String startTimeString;
    String endTimeString;
    if ( this.timeVar.getDataType().equals( DataType.DOUBLE))
    {
      startTimeString = startTimeArray.getDouble( startTimeArray.getIndex() ) + " " + timeVarUnitsString;
      endTimeString = endTimeArray.getDouble( endTimeArray.getIndex() ) + " " + timeVarUnitsString;
    }
    else if ( this.timeVar.getDataType().equals( DataType.FLOAT))
    {
      startTimeString = startTimeArray.getFloat( startTimeArray.getIndex() ) + " " + timeVarUnitsString;
      endTimeString = endTimeArray.getFloat( endTimeArray.getIndex() ) + " " + timeVarUnitsString;
    }
    else if ( this.timeVar.getDataType().equals( DataType.INT ) )
    {
      startTimeString = startTimeArray.getInt( startTimeArray.getIndex() ) + " " + timeVarUnitsString;
      endTimeString = endTimeArray.getInt( endTimeArray.getIndex() ) + " " + timeVarUnitsString;
    }
    else
    {
      String tmpMsg = "Time var <" + this.timeVar.getFullName() + "> is not a double, float, or integer <" + timeVar.getDataType().toString() + ">.";
      //log.error( tmpMsg );
      throw new IllegalArgumentException( tmpMsg);
    }

    startDate = DateUnit.getStandardDate( startTimeString );
    endDate = DateUnit.getStandardDate( endTimeString);

    trajectoryIds = new ArrayList();
    trajectories = new ArrayList();
    trajectoriesMap = new HashMap();
    Array trajArray = this.trajVar.read();
    Index index = trajArray.getIndex();
    for ( int i = 0; i < trajArray.getSize(); i++ )
    {
      String curTrajId;
      if ( this.trajVar.getDataType().equals( DataType.STRING ) )
      {
        curTrajId = (String) trajArray.getObject( index.set( i ) );
      }
      else if ( this.trajVar.getDataType().equals( DataType.DOUBLE ) )
      {
        curTrajId = String.valueOf( trajArray.getDouble( index.set( i ) ) );
      }
      else if ( this.trajVar.getDataType().equals( DataType.FLOAT ) )
      {
        curTrajId = String.valueOf( trajArray.getFloat( index.set( i ) ) );
      }
      else if ( this.trajVar.getDataType().equals( DataType.INT ) )
      {
        curTrajId = String.valueOf( trajArray.getInt( index.set( i ) ) );
      }
      else
      {
        String tmpMsg = "Trajectory var <" + this.trajVar.getFullName() + "> is not a string, double, float, or integer <" + this.trajVar.getDataType().toString() + ">.";
        //log.error( tmpMsg );
        throw new IllegalStateException( tmpMsg );
      }

      MultiTrajectory curTraj = new MultiTrajectory( curTrajId, i, trajectoryNumPoint, startDate, endDate,
                                                     this.trajVar, this.timeVar, timeVarUnitsString,
                                                     this.latVar, this.lonVar, this.elevVar,
                                                     dataVariables, trajectoryVarsMap );
      trajectoryIds.add( curTrajId);
      trajectories.add( curTraj);
      trajectoriesMap.put( curTrajId, curTraj );
    }
  }
Setup needed for all MultiTrajectoryObsDatatypes.

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.