public void testAggCoordVar(NetcdfFile ncfile) {

    Variable time = ncfile.findVariable("time");
    assert null != time;
    assert time.getShortName().equals("time");
    assert time.getRank() == 1 : time.getRank();
    assert time.getShape()[0] == 3;
    assert time.getDataType() == DataType.INT;

    assert time.getDimension(0) == ncfile.findDimension("time");

    try {
      Array data = time.read();

      assert (data instanceof ArrayInt.D1) : data.getClass().getName();
      ArrayInt.D1 dataI = (ArrayInt.D1) data;
      assert dataI.get(0) == 0;
      assert dataI.get(1) == 10;
      assert dataI.get(2) == 99;

    } catch (IOException io) {
      io.printStackTrace();
      assert false;
    }
  }
  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++;
  }
  /**
   * Fill all of the variables/attributes in the ncfile
   *
   * @param ncfile NetcdfFile object which will be filled.
   * @param bst number of seconds since midnight for start of sweep
   * @param yr year of start of each sweep
   * @param m month of start of each sweep
   * @param dda day of start of each sweep
   * @param varList ArrayList of Variables of ncfile
   * @param recHdr java.util.Map with values for Attributes
   */
  public void doNetcdfFileCoordinate(
      ucar.nc2.NetcdfFile ncfile,
      int[] bst,
      short[] yr,
      short[] m,
      short[] dda,
      ArrayList<Variable> varList,
      java.util.Map<String, Number> recHdr) {
    // prepare attribute values

    String[] unit = {" ", "dbZ", "dbZ", "m/sec", "m/sec", "dB"};
    String def_datafile = "SIGMET-IRIS";
    Short header_length = 80;
    Short ray_header_length = 6;
    int ngates = 0;

    float radar_lat =
        recHdr.get("radar_lat").floatValue(); // System.out.println("rad_lat="+radar_lat);
    float radar_lon =
        recHdr.get("radar_lon").floatValue(); // System.out.println("rad_lon="+radar_lon);
    short ground_height =
        recHdr.get("ground_height").shortValue(); // System.out.println("ground_H="+ground_height);
    short radar_height =
        recHdr.get("radar_height").shortValue(); // System.out.println("radar_H="+radar_height);
    int radar_alt =
        (recHdr.get("radar_alt").intValue()) / 100; // System.out.println("rad_alt="+radar_alt);
    short num_rays =
        recHdr.get("num_rays").shortValue(); // System.out.println("HERE!! num_rays="+num_rays);
    float range_first =
        (recHdr.get("range_first").intValue())
            * 0.01f; // System.out.println("range_1st="+range_first);
    float range_last =
        (recHdr.get("range_last").intValue()) * 0.01f; // System.out.println("step="+step);
    short number_sweeps = recHdr.get("number_sweeps").shortValue();
    int nparams = (recHdr.get("nparams").intValue()); // System.out.println("nparams="+nparams);
    // define date/time
    // int last_t=(int)(ray[nparams*number_sweeps-1][num_rays-1].getTime());
    int last_t = volScan.lastRay.getTime();
    String sss1 = Short.toString(m[0]);
    if (sss1.length() < 2) sss1 = "0" + sss1;
    String sss2 = Short.toString(dda[0]);
    if (sss2.length() < 2) sss2 = "0" + sss2;
    String base_date0 = String.valueOf(yr[0]) + "-" + sss1 + "-" + sss2;
    String sss11 = Short.toString(m[number_sweeps - 1]);
    if (sss11.length() < 2) sss11 = "0" + sss11;
    String sss22 = Short.toString(dda[number_sweeps - 1]);
    if (sss22.length() < 2) sss22 = "0" + sss22;
    String base_date1 = String.valueOf(yr[number_sweeps - 1]) + "-" + sss11 + "-" + sss22;
    String start_time = base_date0 + "T" + calcTime(bst[0], 0) + "Z";
    String end_time = base_date1 + "T" + calcTime(bst[number_sweeps - 1], last_t) + "Z";
    ncfile.addAttribute(null, new Attribute("time_coverage_start", start_time));
    ncfile.addAttribute(null, new Attribute("time_coverage_end", end_time));

    // set all of Variables
    try {
      int sz = varList.size();

      ArrayFloat.D2[] dataArr = new ArrayFloat.D2[nparams * number_sweeps];
      Index[] dataIndex = new Index[nparams * number_sweeps];

      Ray[] rtemp = new Ray[(int) num_rays];

      // NCdump.printArray(dataArr[0], "Total_Power", System.out, null);

      Variable[] distanceR = new Variable[number_sweeps];
      ArrayFloat.D1[] distArr = new ArrayFloat.D1[number_sweeps];
      Index[] distIndex = new Index[number_sweeps];
      String distName = "distanceR";
      for (int i = 0; i < number_sweeps; i++) {
        if (number_sweeps > 1) {
          distName = "distanceR_sweep_" + (i + 1);
        }
        for (Variable aVarList : varList) {
          if ((aVarList.getShortName()).equals(distName.trim())) {
            distanceR[i] = aVarList;
            break;
          }
        }
        distArr[i] = (ArrayFloat.D1) Array.factory(DataType.FLOAT, distanceR[i].getShape());
        distIndex[i] = distArr[i].getIndex();

        // for (int jj=0; jj<num_rays; jj++) { rtemp[jj]=ray[i][jj]; }
        ngates = sweep_bins[i];
        float stp = calcStep(range_first, range_last, (short) ngates);
        for (int ii = 0; ii < ngates; ii++) {
          distArr[i].setFloat(distIndex[i].set(ii), (range_first + ii * stp));
        }
      }
      // NCdump.printArray(distArr[0], "distanceR", System.out, null);
      List rgp = volScan.getTotalPowerGroups();
      if (rgp.size() == 0) rgp = volScan.getReflectivityGroups();
      List[] sgp = new ArrayList[number_sweeps];
      for (int i = 0; i < number_sweeps; i++) {
        sgp[i] = (List) rgp.get((short) i);
      }

      Variable[] time = new Variable[number_sweeps];
      ArrayInt.D1[] timeArr = new ArrayInt.D1[number_sweeps];
      Index[] timeIndex = new Index[number_sweeps];
      String t_n = "time";
      for (int i = 0; i < number_sweeps; i++) {
        if (number_sweeps > 1) {
          t_n = "time_sweep_" + (i + 1);
        }
        for (Variable aVarList : varList) {
          if ((aVarList.getShortName()).equals(t_n.trim())) {
            time[i] = aVarList;
            break;
          }
        }

        //                if (time[i].getShape().length == 0) {
        //                    continue;
        //                }
        timeArr[i] = (ArrayInt.D1) Array.factory(DataType.INT, time[i].getShape());
        timeIndex[i] = timeArr[i].getIndex();
        List rlist = sgp[i];

        for (int jj = 0; jj < num_rays; jj++) {
          rtemp[jj] = (Ray) rlist.get(jj);
        } // ray[i][jj]; }
        for (int jj = 0; jj < num_rays; jj++) {
          timeArr[i].setInt(timeIndex[i].set(jj), rtemp[jj].getTime());
        }
      }

      // NCdump.printArray(timeArr[0], "time", System.out, null);

      Variable[] azimuthR = new Variable[number_sweeps];
      ArrayFloat.D1[] azimArr = new ArrayFloat.D1[number_sweeps];
      Index[] azimIndex = new Index[number_sweeps];
      String azimName = "azimuthR";
      for (int i = 0; i < number_sweeps; i++) {
        if (number_sweeps > 1) {
          azimName = "azimuthR_sweep_" + (i + 1);
        }
        for (Variable aVarList : varList) {
          if ((aVarList.getShortName()).equals(azimName.trim())) {
            azimuthR[i] = aVarList;
            break;
          }
        }
        azimArr[i] = (ArrayFloat.D1) Array.factory(DataType.FLOAT, azimuthR[i].getShape());
        azimIndex[i] = azimArr[i].getIndex();
        List rlist = sgp[i];

        for (int jj = 0; jj < num_rays; jj++) {
          rtemp[jj] = (Ray) rlist.get(jj);
        } // ray[i][jj]; }
        for (int jj = 0; jj < num_rays; jj++) {
          azimArr[i].setFloat(azimIndex[i].set(jj), rtemp[jj].getAz());
        }
      }
      // NCdump.printArray(azimArr[0], "azimuthR", System.out, null);

      Variable[] elevationR = new Variable[number_sweeps];
      ArrayFloat.D1[] elevArr = new ArrayFloat.D1[number_sweeps];
      Index[] elevIndex = new Index[number_sweeps];
      String elevName = "elevationR";
      for (int i = 0; i < number_sweeps; i++) {
        if (number_sweeps > 1) {
          elevName = "elevationR_sweep_" + (i + 1);
        }
        for (Variable aVarList : varList) {
          if ((aVarList.getShortName()).equals(elevName.trim())) {
            elevationR[i] = aVarList;
            break;
          }
        }
        elevArr[i] = (ArrayFloat.D1) Array.factory(DataType.FLOAT, elevationR[i].getShape());
        elevIndex[i] = elevArr[i].getIndex();
        List rlist = sgp[i];

        for (int jj = 0; jj < num_rays; jj++) {
          rtemp[jj] = (Ray) rlist.get(jj);
        } // ray[i][jj]; }
        for (int jj = 0; jj < num_rays; jj++) {
          elevArr[i].setFloat(elevIndex[i].set(jj), rtemp[jj].getElev());
        }
      }
      // NCdump.printArray(elevArr[0], "elevationR", System.out, null);

      Variable numGates = null;
      for (int i = 0; i < number_sweeps; i++) {
        for (Variable aVarList : varList) {
          if ((aVarList.getShortName()).equals("numGates")) {
            numGates = aVarList;
            break;
          }
        }
      }
      ArrayInt.D1 gatesArr = (ArrayInt.D1) Array.factory(DataType.INT, numGates.getShape());
      Index gatesIndex = gatesArr.getIndex();

      for (int i = 0; i < number_sweeps; i++) {
        List rlist = sgp[i];
        for (int jj = 0; jj < num_rays; jj++) {
          rtemp[jj] = (Ray) rlist.get(jj);
        } // ray[i][jj]; }
        ngates = rtemp[0].getBins();
        gatesArr.setInt(gatesIndex.set(i), ngates);
      }

      for (int i = 0; i < number_sweeps; i++) {
        distanceR[i].setCachedData(distArr[i], false);
        time[i].setCachedData(timeArr[i], false);
        azimuthR[i].setCachedData(azimArr[i], false);
        elevationR[i].setCachedData(elevArr[i], false);
      }
      numGates.setCachedData(gatesArr, false);
      // startSweep.setCachedData(sweepArr, false);

      //          -------------------------------------------------
      // int b=(int)ray[0][0].getBins();

      // -- Test of readData() and readToByteChannel() -----------------
      /*
      Range r1=new Range(356, 359);
      Range r2=new Range(0, 15);
      java.util.List arlist=new ArrayList();
      arlist.add(r1);
      arlist.add(r2);
      Array testArr=readData(v[0], new Section(arlist));
      NCdump.printArray(testArr, "Total_Power_sweep_1", System.out, null);
      WritableByteChannel channel=new FileOutputStream(new File("C:\\netcdf\\tt.dat")).getChannel();
      long ikk=readToByteChannel(v[0], new Section(arlist), channel);
      System.out.println("IKK="+ikk);
      channel.close();
            */
      // ---------------------------------------------------

    } catch (Exception e) {
      System.out.println(e.toString());
      e.printStackTrace();
    }
  } // ----------- end of doNetcdf ----------------------------------
  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)));
  }
 /**
  * Make the station variables from a representative station
  *
  * @param stations list of stations
  * @param dim station dimension
  * @return the list of variables
  */
 protected List<Variable> makeStationVars(List<GempakStation> stations, Dimension dim) {
   int numStations = stations.size();
   boolean useSTID = true;
   for (GempakStation station : stations) {
     if (station.getSTID().equals("")) {
       useSTID = false;
       break;
     }
   }
   List<Variable> vars = new ArrayList<Variable>();
   List<String> stnKeyNames = gemreader.getStationKeyNames();
   for (String varName : stnKeyNames) {
     Variable v = makeStationVariable(varName, dim);
     // use STNM or STID as the name or description
     Attribute stIDAttr = new Attribute("standard_name", "station_id");
     if (varName.equals(GempakStation.STID) && useSTID) {
       v.addAttribute(stIDAttr);
     }
     if (varName.equals(GempakStation.STNM) && !useSTID) {
       v.addAttribute(stIDAttr);
     }
     vars.add(v);
   }
   // see if we fill these in completely now
   if ((dim != null) && (numStations > 0)) {
     for (Variable v : vars) {
       Array varArray;
       if (v.getDataType().equals(DataType.CHAR)) {
         int[] shape = v.getShape();
         varArray = new ArrayChar.D2(shape[0], shape[1]);
       } else {
         varArray = get1DArray(v.getDataType(), numStations);
       }
       int index = 0;
       String varname = v.getFullName();
       for (GempakStation stn : stations) {
         String test = "";
         if (varname.equals(GempakStation.STID)) {
           test = stn.getName();
         } else if (varname.equals(GempakStation.STNM)) {
           ((ArrayInt.D1) varArray)
               .set(
                   index,
                   // (int) (stn.getSTNM() / 10));
                   (int) (stn.getSTNM()));
         } else if (varname.equals(GempakStation.SLAT)) {
           ((ArrayFloat.D1) varArray).set(index, (float) stn.getLatitude());
         } else if (varname.equals(GempakStation.SLON)) {
           ((ArrayFloat.D1) varArray).set(index, (float) stn.getLongitude());
         } else if (varname.equals(GempakStation.SELV)) {
           ((ArrayFloat.D1) varArray).set(index, (float) stn.getAltitude());
         } else if (varname.equals(GempakStation.STAT)) {
           test = stn.getSTAT();
         } else if (varname.equals(GempakStation.COUN)) {
           test = stn.getCOUN();
         } else if (varname.equals(GempakStation.STD2)) {
           test = stn.getSTD2();
         } else if (varname.equals(GempakStation.SPRI)) {
           ((ArrayInt.D1) varArray).set(index, stn.getSPRI());
         } else if (varname.equals(GempakStation.SWFO)) {
           test = stn.getSWFO();
         } else if (varname.equals(GempakStation.WFO2)) {
           test = stn.getWFO2();
         }
         if (!test.equals("")) {
           ((ArrayChar.D2) varArray).setString(index, test);
         }
         index++;
       }
       v.setCachedData(varArray, false);
     }
   }
   return vars;
 }
  @Test
  public void testArraySubset() throws IOException {
    DODSNetcdfFile dodsfile = TestDODSRead.open("test.02?i32[1:10],f64[2:2:10]");

    Variable v = null;
    Array a = null;

    // int32
    assert (null != (v = dodsfile.findVariable("i32")));
    assert v.getFullName().equals("i32");
    assert v.getRank() == 1;
    assert v.getSize() == 10;
    assert v.getDataType() == DataType.INT;
    a = v.read();
    assert a.getRank() == 1;
    assert a.getSize() == 25;
    assert a.getElementType() == int.class;
    assert a instanceof ArrayInt.D1;

    ArrayInt.D1 ai = (ArrayInt.D1) a;
    for (int i = 0; i < 10; i++) {
      int val = ai.get(i);
      assert (val == i * 2048) : val + " != " + (i * 2048);
    }

    // uint16
    assert null == (v = dodsfile.findVariable("ui16"));
    assert null == (v = dodsfile.findVariable("ui32"));

    // double
    assert (null != (v = dodsfile.findVariable("f64")));
    assert v.getFullName().equals("f64");
    assert v.getRank() == 1;
    assert v.getSize() == 5;
    assert v.getDataType() == DataType.DOUBLE : v.getDataType();
    a = v.read();
    assert a.getRank() == 1;
    assert a.getSize() == 25;
    assert a.getElementType() == double.class;
    assert a instanceof ArrayDouble.D1;
    ArrayDouble.D1 ad = (ArrayDouble.D1) a;
    double[] tFloat64 =
        new double[] {
          1.0,
          0.9999500004166653,
          0.9998000066665778,
          0.9995500337489875,
          0.9992001066609779,
          0.9987502603949663,
          0.9982005399352042,
          0.9975510002532796,
          0.9968017063026194,
          0.9959527330119943,
          0.9950041652780257,
          0.9939560979566968,
          0.9928086358538663,
          0.9915618937147881,
          0.9902159962126371,
          0.9887710779360422,
          0.9872272833756269,
          0.9855847669095608,
          0.9838436927881214,
          0.9820042351172703,
          0.9800665778412416,
          0.9780309147241483,
          0.9758974493306055,
          0.9736663950053749,
          0.9713379748520297
        };

    for (int i = 0; i < 5; i++) {
      double val = ad.get(i);
      assert Misc.closeEnough(val, tFloat64[i], 1.0e-9);
    }

    dodsfile.close();
  }