public void testAggCoordVarSubsetDefeatLocalCache(NetcdfFile ncfile)
      throws InvalidRangeException, IOException {
    Variable time = ncfile.findVariable("time");
    assert null != time;

    assert time.getShortName().equals("time");
    assert time.getRank() == 1;
    assert time.getSize() == 3;
    assert time.getShape()[0] == 3;
    assert time.getDataType() == DataType.DOUBLE;

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

    time.setCachedData(null, false);
    Array data = time.read("1:2");
    assert data.getRank() == 1;
    assert data.getSize() == 2;
    assert data.getShape()[0] == 2;
    assert data.getElementType() == double.class;

    int count = 0;
    IndexIterator dataI = data.getIndexIterator();
    while (dataI.hasNext()) {
      assert Misc.closeEnough(dataI.getDoubleNext(), result[count + 1]);
      count++;
    }

    time.setCachedData(null, false);
    data = time.read("0:2:2");
    assert data.getRank() == 1;
    assert data.getSize() == 2;
    assert data.getShape()[0] == 2;
    assert data.getElementType() == double.class;

    count = 0;
    dataI = data.getIndexIterator();
    while (dataI.hasNext()) {
      assert Misc.closeEnough(dataI.getDoubleNext(), result[count * 2]);
      count++;
    }
  }
  /**
   * Add this as a variable to the netCDF file
   *
   * @param ncfile the netCDF file
   * @param g the group in the file
   */
  void addToNetcdfFile(NetcdfFile ncfile, Group g) {
    Variable v = new Variable(ncfile, g, null, getName());
    v.setDimensions(v.getShortName());
    v.setDataType(DataType.STRING);
    v.addAttribute(new Attribute("long_name", "ensemble"));
    v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Ensemble.toString()));

    String[] data = new String[getNEnsembles()];

    for (int i = 0; i < getNEnsembles(); i++) {
      EnsCoord ec = ensCoords.get(i);
      data[i] = Grib2Tables.codeTable4_6(ec.type) + " " + ec.number;
    }
    Array dataArray = Array.factory(DataType.STRING, new int[] {getNEnsembles()}, data);
    v.setCachedData(dataArray, false);

    ncfile.addVariable(g, v);
  }
  /**
   * 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 ----------------------------------
Exemple #4
0
  private FeatureType amendGrid(
      Element gridElem, NetcdfFile ncfile, Group parent, String location) {
    List<Dimension> unknownDims = new ArrayList<>();

    // always has x and y dimension
    String xdimSizeS = gridElem.getChild("XDim").getText().trim();
    String ydimSizeS = gridElem.getChild("YDim").getText().trim();
    int xdimSize = Integer.parseInt(xdimSizeS);
    int ydimSize = Integer.parseInt(ydimSizeS);
    parent.addDimensionIfNotExists(new Dimension("XDim", xdimSize));
    parent.addDimensionIfNotExists(new Dimension("YDim", ydimSize));

    /* see HdfEosModisConvention
    UpperLeftPointMtrs=(-20015109.354000,1111950.519667)
    		LowerRightMtrs=(-18903158.834333,-0.000000)
    		Projection=GCTP_SNSOID
    		ProjParams=(6371007.181000,0,0,0,0,0,0,0,0,0,0,0,0)
    		SphereCode=-1
     */
    Element proj = gridElem.getChild("Projection");
    if (proj != null) {
      Variable crs = new Variable(ncfile, parent, null, HDFEOS_CRS);
      crs.setDataType(DataType.SHORT);
      crs.setDimensions(""); // scalar
      crs.setCachedData(Array.makeArray(DataType.SHORT, 1, 0, 0)); // fake data
      parent.addVariable(crs);

      addAttributeIfExists(gridElem, HDFEOS_CRS_Projection, crs, false);
      addAttributeIfExists(gridElem, HDFEOS_CRS_UpperLeft, crs, true);
      addAttributeIfExists(gridElem, HDFEOS_CRS_LowerRight, crs, true);
      addAttributeIfExists(gridElem, HDFEOS_CRS_ProjParams, crs, true);
      addAttributeIfExists(gridElem, HDFEOS_CRS_SphereCode, crs, false);
    }

    // global Dimensions
    Element d = gridElem.getChild("Dimension");
    List<Element> dims = d.getChildren();
    for (Element elem : dims) {
      String name = elem.getChild("DimensionName").getText().trim();
      name = NetcdfFile.makeValidCdmObjectName(name);
      if (name.equalsIgnoreCase("scalar")) continue;

      String sizeS = elem.getChild("Size").getText().trim();
      int length = Integer.parseInt(sizeS);
      Dimension old = parent.findDimension(name);
      if ((old == null) || (old.getLength() != length)) {
        if (length > 0) {
          Dimension dim = new Dimension(name, length);
          if (parent.addDimensionIfNotExists(dim) && showWork)
            System.out.printf(" Add dimension %s %n", dim);
        } else {
          log.warn("Dimension {} has size {} {} ", sizeS, name, location);
          Dimension udim = new Dimension(name, 1);
          udim.setGroup(parent);
          unknownDims.add(udim);
          if (showWork) System.out.printf(" Add dimension %s %n", udim);
        }
      }
    }

    // Geolocation Variables
    Group geoFieldsG = parent.findGroup(GEOLOC_FIELDS);
    if (geoFieldsG == null) geoFieldsG = parent.findGroup(GEOLOC_FIELDS2);

    if (geoFieldsG != null) {
      Element floc = gridElem.getChild("GeoField");
      List<Element> varsLoc = floc.getChildren();
      for (Element elem : varsLoc) {
        String varname = elem.getChild("GeoFieldName").getText().trim();
        Variable v = geoFieldsG.findVariable(varname);
        // if (v == null)
        //  v = geoFieldsG.findVariable( H4header.createValidObjectName(varname));
        assert v != null : varname;

        Element dimList = elem.getChild("DimList");
        List<Element> values = dimList.getChildren("value");
        setSharedDimensions(v, values, unknownDims, location);
      }
    }

    // Data Variables
    Group dataG = parent.findGroup(DATA_FIELDS);
    if (dataG == null)
      dataG =
          parent.findGroup(
              DATA_FIELDS2); // eg C:\data\formats\hdf4\eos\mopitt\MOP03M-200501-L3V81.0.1.hdf

    if (dataG != null) {
      Element f = gridElem.getChild("DataField");
      List<Element> vars = f.getChildren();
      for (Element elem : vars) {
        String varname = elem.getChild("DataFieldName").getText().trim();
        varname = NetcdfFile.makeValidCdmObjectName(varname);
        Variable v = dataG.findVariable(varname);
        // if (v == null)
        //  v = dataG.findVariable( H4header.createValidObjectName(varname));
        assert v != null : varname;

        Element dimList = elem.getChild("DimList");
        List<Element> values = dimList.getChildren("value");
        setSharedDimensions(v, values, unknownDims, location);
      }

      // get projection
      String projS = null;
      Element projElem = gridElem.getChild("Projection");
      if (projElem != null) projS = projElem.getText().trim();
      boolean isLatLon = "GCTP_GEO".equals(projS);

      // look for XDim, YDim coordinate variables
      if (isLatLon) {
        for (Variable v : dataG.getVariables()) {
          if (v.isCoordinateVariable()) {
            if (v.getShortName().equals("YDim")) {
              v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Lat.toString()));
              v.addAttribute(new Attribute(CDM.UNITS, CDM.LAT_UNITS));
            }
            if (v.getShortName().equals("XDim"))
              v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Lon.toString()));
          }
        }
      }
    }
    return FeatureType.GRID;
  }
Exemple #5
0
  private FeatureType amendSwath(NetcdfFile ncfile, Element swathElem, Group parent) {
    FeatureType featureType = FeatureType.SWATH;
    List<Dimension> unknownDims = new ArrayList<>();

    // Dimensions
    Element d = swathElem.getChild("Dimension");
    List<Element> dims = d.getChildren();
    for (Element elem : dims) {
      String name = elem.getChild("DimensionName").getText().trim();
      name = NetcdfFile.makeValidCdmObjectName(name);

      if (name.equalsIgnoreCase("scalar")) continue;
      String sizeS = elem.getChild("Size").getText().trim();
      int length = Integer.parseInt(sizeS);
      if (length > 0) {
        Dimension dim = parent.findDimensionLocal(name);
        if (dim != null) { // already added - may be dimension scale ?
          if (dim.getLength() != length) { // ok as long as it matches
            log.error("Conflicting Dimensions = {} {}", dim, ncfile.getLocation());
            throw new IllegalStateException("Conflicting Dimensions = " + name);
          }
        } else {
          dim = new Dimension(name, length);
          if (parent.addDimensionIfNotExists(dim) && showWork)
            System.out.printf(" Add dimension %s %n", dim);
        }
      } else {
        log.warn("Dimension " + name + " has size " + sizeS, ncfile.getLocation());
        Dimension udim = new Dimension(name, 1);
        udim.setGroup(parent);
        unknownDims.add(udim);
        if (showWork) System.out.printf(" Add dimension %s %n", udim);
      }
    }

    // Dimension Maps
    Element dmap = swathElem.getChild("DimensionMap");
    List<Element> dimMaps = dmap.getChildren();
    for (Element elem : dimMaps) {
      String geoDimName = elem.getChild("GeoDimension").getText().trim();
      geoDimName = NetcdfFile.makeValidCdmObjectName(geoDimName);
      String dataDimName = elem.getChild("DataDimension").getText().trim();
      dataDimName = NetcdfFile.makeValidCdmObjectName(dataDimName);

      String offsetS = elem.getChild("Offset").getText().trim();
      String incrS = elem.getChild("Increment").getText().trim();
      int offset = Integer.parseInt(offsetS);
      int incr = Integer.parseInt(incrS);

      // make new variable for this dimension map
      Variable v = new Variable(ncfile, parent, null, dataDimName);
      v.setDimensions(geoDimName);
      v.setDataType(DataType.INT);
      int npts = (int) v.getSize();
      Array data = Array.makeArray(v.getDataType(), npts, offset, incr);
      v.setCachedData(data, true);
      v.addAttribute(new Attribute("_DimensionMap", ""));
      parent.addVariable(v);
      if (showWork) System.out.printf(" Add dimensionMap %s %n", v);
    }

    // Geolocation Variables
    Group geoFieldsG = parent.findGroup(GEOLOC_FIELDS);
    if (geoFieldsG == null) geoFieldsG = parent.findGroup(GEOLOC_FIELDS2);
    if (geoFieldsG != null) {
      Variable latAxis = null, lonAxis = null;
      Element floc = swathElem.getChild("GeoField");
      List<Element> varsLoc = floc.getChildren();
      for (Element elem : varsLoc) {
        String varname = elem.getChild("GeoFieldName").getText().trim();
        Variable v = geoFieldsG.findVariable(varname);
        // if (v == null)
        //  v = geoFieldsG.findVariable( H4header.createValidObjectName(varname));
        assert v != null : varname;
        AxisType axis = addAxisType(ncfile, v);
        if (axis == AxisType.Lat) latAxis = v;
        if (axis == AxisType.Lon) lonAxis = v;

        Element dimList = elem.getChild("DimList");
        List<Element> values = dimList.getChildren("value");
        setSharedDimensions(v, values, unknownDims, ncfile.getLocation());
        if (showWork) System.out.printf(" set coordinate %s %n", v);
      }
      if ((latAxis != null) && (lonAxis != null)) {
        List<Dimension> xyDomain = CoordinateSystem.makeDomain(new Variable[] {latAxis, lonAxis});
        if (xyDomain.size() < 2) featureType = FeatureType.PROFILE; // ??
      }
    }

    // Data Variables
    Group dataG = parent.findGroup(DATA_FIELDS);
    if (dataG == null) dataG = parent.findGroup(DATA_FIELDS2);
    if (dataG != null) {
      Element f = swathElem.getChild("DataField");
      List<Element> vars = f.getChildren();
      for (Element elem : vars) {
        Element dataFieldNameElem = elem.getChild("DataFieldName");
        if (dataFieldNameElem == null) continue;
        String varname = NetcdfFile.makeValidCdmObjectName(dataFieldNameElem.getText().trim());
        Variable v = dataG.findVariable(varname);
        // if (v == null)
        //  v = dataG.findVariable( H4header.createValidObjectName(varname));
        if (v == null) {
          log.error("Cant find variable {} {}", varname, ncfile.getLocation());
          continue;
        }

        Element dimList = elem.getChild("DimList");
        List<Element> values = dimList.getChildren("value");
        setSharedDimensions(v, values, unknownDims, ncfile.getLocation());
      }
    }

    return featureType;
  }
 /**
  * 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;
 }
  /**
   * Add this coord as a variable in the netCDF file
   *
   * @param ncfile netCDF file to add to
   * @param g group in file
   */
  void addToNetcdfFile(NetcdfFile ncfile, Group g) {
    if (dontUseVertical) {
      typicalRecord = null;
      return;
    }

    if (g == null) {
      g = ncfile.getRootGroup();
    }

    // coordinate axis
    Variable v = new Variable(ncfile, g, null, getVariableName());
    v.setDataType(DataType.DOUBLE);

    String desc = lookup.getLevelDescription(typicalRecord);
    if (lookup instanceof Grib2GridTableLookup && usesBounds) {
      desc = "Layer between " + desc;
    }

    v.addAttribute(new Attribute("long_name", desc));
    v.addAttribute(new Attribute("units", lookup.getLevelUnit(typicalRecord)));

    // positive attribute needed for CF-1 Height and Pressure
    if (positive != null) {
      v.addAttribute(new Attribute("positive", positive));
    }

    if (units != null) {
      AxisType axisType;
      if (SimpleUnit.isCompatible("millibar", units)) {
        axisType = AxisType.Pressure;
      } else if (SimpleUnit.isCompatible("m", units)) {
        axisType = AxisType.Height;
      } else {
        axisType = AxisType.GeoZ;
      }

      if (lookup instanceof Grib2GridTableLookup || lookup instanceof Grib1GridTableLookup) {
        v.addAttribute(
            new Attribute("GRIB_level_type", Integer.toString(typicalRecord.getLevelType1())));
      } else {
        v.addAttribute(
            new Attribute("level_type", Integer.toString(typicalRecord.getLevelType1())));
      }
      v.addAttribute(new Attribute(_Coordinate.AxisType, axisType.toString()));
    }

    if (coordValues == null) {
      coordValues = new double[levels.size()];
      for (int i = 0; i < levels.size(); i++) {
        LevelCoord lc = (LevelCoord) levels.get(i);
        coordValues[i] = lc.mid;
      }
    }
    Array dataArray = Array.factory(DataType.DOUBLE, new int[] {coordValues.length}, coordValues);

    v.setDimensions(getVariableName());
    v.setCachedData(dataArray, true);

    ncfile.addVariable(g, v);

    if (usesBounds) {
      String boundsDimName = "bounds_dim";
      if (g.findDimension(boundsDimName) == null) {
        ncfile.addDimension(g, new Dimension(boundsDimName, 2, true));
      }

      String bname = getVariableName() + "_bounds";
      v.addAttribute(new Attribute("bounds", bname));
      v.addAttribute(new Attribute(_Coordinate.ZisLayer, "true"));

      Variable b = new Variable(ncfile, g, null, bname);
      b.setDataType(DataType.DOUBLE);
      b.setDimensions(getVariableName() + " " + boundsDimName);
      b.addAttribute(new Attribute("long_name", "bounds for " + v.getName()));
      b.addAttribute(new Attribute("units", lookup.getLevelUnit(typicalRecord)));

      Array boundsArray = Array.factory(DataType.DOUBLE, new int[] {coordValues.length, 2});
      ucar.ma2.Index ima = boundsArray.getIndex();
      for (int i = 0; i < coordValues.length; i++) {
        LevelCoord lc = (LevelCoord) levels.get(i);
        boundsArray.setDouble(ima.set(i, 0), lc.value1);
        boundsArray.setDouble(ima.set(i, 1), lc.value2);
      }
      b.setCachedData(boundsArray, true);

      ncfile.addVariable(g, b);
    }

    if (factors != null) {
      // check if already created
      if (g == null) {
        g = ncfile.getRootGroup();
      }
      if (g.findVariable("hybrida") != null) return;
      v.addAttribute(new Attribute("standard_name", "atmosphere_hybrid_sigma_pressure_coordinate"));
      v.addAttribute(new Attribute("formula_terms", "ap: hybrida b: hybridb ps: Pressure"));
      // create  hybrid factor variables
      // add hybrida variable
      Variable ha = new Variable(ncfile, g, null, "hybrida");
      ha.setDataType(DataType.DOUBLE);
      ha.addAttribute(new Attribute("long_name", "level_a_factor"));
      ha.addAttribute(new Attribute("units", ""));
      ha.setDimensions(getVariableName());
      // add data
      int middle = factors.length / 2;
      double[] adata;
      double[] bdata;
      if (levels.size() < middle) { // only partial data wanted
        adata = new double[levels.size()];
        bdata = new double[levels.size()];
      } else {
        adata = new double[middle];
        bdata = new double[middle];
      }
      for (int i = 0; i < middle && i < levels.size(); i++) adata[i] = factors[i];
      Array haArray = Array.factory(DataType.DOUBLE, new int[] {adata.length}, adata);
      ha.setCachedData(haArray, true);
      ncfile.addVariable(g, ha);

      // add hybridb variable
      Variable hb = new Variable(ncfile, g, null, "hybridb");
      hb.setDataType(DataType.DOUBLE);
      hb.addAttribute(new Attribute("long_name", "level_b_factor"));
      hb.addAttribute(new Attribute("units", ""));
      hb.setDimensions(getVariableName());
      // add data
      for (int i = 0; i < middle && i < levels.size(); i++) bdata[i] = factors[i + middle];
      Array hbArray = Array.factory(DataType.DOUBLE, new int[] {bdata.length}, bdata);
      hb.setCachedData(hbArray, true);
      ncfile.addVariable(g, hb);

      /*  // TODO: delete next time modifying code
      double[] adata = new double[ middle ];
      for( int i = 0; i < middle; i++ )
        adata[ i ] = factors[ i ];
      Array haArray = Array.factory(DataType.DOUBLE, new int[]{adata.length}, adata);
      ha.setCachedData(haArray, true);
      ncfile.addVariable(g, ha);

      // add hybridb variable
      Variable hb = new Variable(ncfile, g, null, "hybridb");
      hb.setDataType(DataType.DOUBLE);
      hb.addAttribute(new Attribute("long_name",  "level_b_factor" ));
      //hb.addAttribute(new Attribute("standard_name", "atmosphere_hybrid_sigma_pressure_coordinate" ));
      hb.addAttribute(new Attribute("units", ""));
      hb.setDimensions(getVariableName());
      // add data
      double[] bdata = new double[ middle ];
      for( int i = 0; i < middle; i++ )
        bdata[ i ] = factors[ i + middle ];
      Array hbArray = Array.factory(DataType.DOUBLE, new int[]{bdata.length}, bdata);
      hb.setCachedData(hbArray, true);
      ncfile.addVariable(g, hb);
      */
    }
  }
  private void makeCoordinateDataWithMissing(
      int datatype,
      Variable time,
      Variable elev,
      Variable azi,
      Variable nradialsVar,
      Variable ngatesVar,
      List groups) {

    Array timeData = Array.factory(time.getDataType().getPrimitiveClassType(), time.getShape());
    Index timeIndex = timeData.getIndex();

    Array elevData = Array.factory(elev.getDataType().getPrimitiveClassType(), elev.getShape());
    Index elevIndex = elevData.getIndex();

    Array aziData = Array.factory(azi.getDataType().getPrimitiveClassType(), azi.getShape());
    Index aziIndex = aziData.getIndex();

    Array nradialsData =
        Array.factory(nradialsVar.getDataType().getPrimitiveClassType(), nradialsVar.getShape());
    IndexIterator nradialsIter = nradialsData.getIndexIterator();

    Array ngatesData =
        Array.factory(ngatesVar.getDataType().getPrimitiveClassType(), ngatesVar.getShape());
    IndexIterator ngatesIter = ngatesData.getIndexIterator();

    // first fill with missing data
    IndexIterator ii = timeData.getIndexIterator();
    while (ii.hasNext()) ii.setIntNext(MISSING_INT);

    ii = elevData.getIndexIterator();
    while (ii.hasNext()) ii.setFloatNext(MISSING_FLOAT);

    ii = aziData.getIndexIterator();
    while (ii.hasNext()) ii.setFloatNext(MISSING_FLOAT);

    // now set the  coordinate variables from the Cinrad2Record radial
    int last_msecs = Integer.MIN_VALUE;
    int nscans = groups.size();
    try {
      for (int scan = 0; scan < nscans; scan++) {
        List scanGroup = (List) groups.get(scan);
        int nradials = scanGroup.size();

        Cinrad2Record first = null;
        for (int j = 0; j < nradials; j++) {
          Cinrad2Record r = (Cinrad2Record) scanGroup.get(j);
          if (first == null) first = r;

          int radial = r.radial_num - 1;
          timeData.setInt(timeIndex.set(scan, radial), r.data_msecs);
          elevData.setFloat(elevIndex.set(scan, radial), r.getElevation());
          aziData.setFloat(aziIndex.set(scan, radial), r.getAzimuth());

          if (r.data_msecs < last_msecs)
            logger.warn("makeCoordinateData time out of order " + r.data_msecs);
          last_msecs = r.data_msecs;
        }

        nradialsIter.setIntNext(nradials);
        ngatesIter.setIntNext(first.getGateCount(datatype));
      }
    } catch (java.lang.ArrayIndexOutOfBoundsException ae) {
      logger.debug("Cinrad2IOSP.uncompress ", ae);
    }
    time.setCachedData(timeData, false);
    elev.setCachedData(elevData, false);
    azi.setCachedData(aziData, false);
    nradialsVar.setCachedData(nradialsData, false);
    ngatesVar.setCachedData(ngatesData, false);
  }
  private void makeCoordinateData(
      int datatype,
      Variable time,
      Variable elev,
      Variable azi,
      Variable nradialsVar,
      Variable ngatesVar,
      List groups) {

    Array timeData = Array.factory(time.getDataType().getPrimitiveClassType(), time.getShape());
    IndexIterator timeDataIter = timeData.getIndexIterator();

    Array elevData = Array.factory(elev.getDataType().getPrimitiveClassType(), elev.getShape());
    IndexIterator elevDataIter = elevData.getIndexIterator();

    Array aziData = Array.factory(azi.getDataType().getPrimitiveClassType(), azi.getShape());
    IndexIterator aziDataIter = aziData.getIndexIterator();

    Array nradialsData =
        Array.factory(nradialsVar.getDataType().getPrimitiveClassType(), nradialsVar.getShape());
    IndexIterator nradialsIter = nradialsData.getIndexIterator();

    Array ngatesData =
        Array.factory(ngatesVar.getDataType().getPrimitiveClassType(), ngatesVar.getShape());
    IndexIterator ngatesIter = ngatesData.getIndexIterator();

    int last_msecs = Integer.MIN_VALUE;
    int nscans = groups.size();
    int maxRadials = volScan.getMaxRadials();
    for (int i = 0; i < nscans; i++) {
      List scanGroup = (List) groups.get(i);
      int nradials = scanGroup.size();

      Cinrad2Record first = null;
      for (int j = 0; j < nradials; j++) {
        Cinrad2Record r = (Cinrad2Record) scanGroup.get(j);
        if (first == null) first = r;

        timeDataIter.setIntNext(r.data_msecs);
        elevDataIter.setFloatNext(r.getElevation());
        aziDataIter.setFloatNext(r.getAzimuth());

        if (r.data_msecs < last_msecs)
          logger.warn("makeCoordinateData time out of order " + r.data_msecs);
        last_msecs = r.data_msecs;
      }

      for (int j = nradials; j < maxRadials; j++) {
        timeDataIter.setIntNext(MISSING_INT);
        elevDataIter.setFloatNext(MISSING_FLOAT);
        aziDataIter.setFloatNext(MISSING_FLOAT);
      }

      nradialsIter.setIntNext(nradials);
      ngatesIter.setIntNext(first.getGateCount(datatype));
    }

    time.setCachedData(timeData, false);
    elev.setCachedData(elevData, false);
    azi.setCachedData(aziData, false);
    nradialsVar.setCachedData(nradialsData, false);
    ngatesVar.setCachedData(ngatesData, false);
  }
  public Variable makeVariable(
      NetcdfFile ncfile,
      int datatype,
      String shortName,
      String longName,
      String abbrev,
      List groups)
      throws IOException {
    int nscans = groups.size();

    if (nscans == 0) {
      throw new IllegalStateException("No data for " + shortName);
    }

    // get representative record
    List firstGroup = (List) groups.get(0);
    Cinrad2Record firstRecord = (Cinrad2Record) firstGroup.get(0);
    int ngates = firstRecord.getGateCount(datatype);

    String scanDimName = "scan" + abbrev;
    String gateDimName = "gate" + abbrev;
    Dimension scanDim = new Dimension(scanDimName, nscans);
    Dimension gateDim = new Dimension(gateDimName, ngates);
    ncfile.addDimension(null, scanDim);
    ncfile.addDimension(null, gateDim);

    ArrayList dims = new ArrayList();
    dims.add(scanDim);
    dims.add(radialDim);
    dims.add(gateDim);

    Variable v = new Variable(ncfile, null, null, shortName);
    v.setDataType(DataType.BYTE);
    v.setDimensions(dims);
    ncfile.addVariable(null, v);

    v.addAttribute(new Attribute(CDM.UNITS, Cinrad2Record.getDatatypeUnits(datatype)));
    v.addAttribute(new Attribute(CDM.LONG_NAME, longName));

    byte[] b = new byte[2];
    b[0] = Cinrad2Record.MISSING_DATA;
    b[1] = Cinrad2Record.BELOW_THRESHOLD;
    Array missingArray = Array.factory(DataType.BYTE.getPrimitiveClassType(), new int[] {2}, b);

    v.addAttribute(new Attribute(CDM.MISSING_VALUE, missingArray));
    v.addAttribute(
        new Attribute("signal_below_threshold", new Byte(Cinrad2Record.BELOW_THRESHOLD)));
    v.addAttribute(
        new Attribute(CDM.SCALE_FACTOR, new Float(Cinrad2Record.getDatatypeScaleFactor(datatype))));
    v.addAttribute(
        new Attribute(CDM.ADD_OFFSET, new Float(Cinrad2Record.getDatatypeAddOffset(datatype))));
    v.addAttribute(new Attribute(CDM.UNSIGNED, "true"));

    ArrayList dim2 = new ArrayList();
    dim2.add(scanDim);
    dim2.add(radialDim);

    // add time coordinate variable
    String timeCoordName = "time" + abbrev;
    Variable timeVar = new Variable(ncfile, null, null, timeCoordName);
    timeVar.setDataType(DataType.INT);
    timeVar.setDimensions(dim2);
    ncfile.addVariable(null, timeVar);

    // int julianDays = volScan.getTitleJulianDays();
    // Date d = Cinrad2Record.getDate( julianDays, 0);
    // Date d = Cinrad2Record.getDate(volScan.getTitleJulianDays(), volScan.getTitleMsecs());
    Date d = volScan.getStartDate();
    String units = "msecs since " + formatter.toDateTimeStringISO(d);

    timeVar.addAttribute(new Attribute(CDM.LONG_NAME, "time since base date"));
    timeVar.addAttribute(new Attribute(CDM.UNITS, units));
    timeVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Integer(MISSING_INT)));
    timeVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Time.toString()));

    // add elevation coordinate variable
    String elevCoordName = "elevation" + abbrev;
    Variable elevVar = new Variable(ncfile, null, null, elevCoordName);
    elevVar.setDataType(DataType.FLOAT);
    elevVar.setDimensions(dim2);
    ncfile.addVariable(null, elevVar);

    elevVar.addAttribute(new Attribute(CDM.UNITS, "degrees"));
    elevVar.addAttribute(
        new Attribute(
            CDM.LONG_NAME,
            "elevation angle in degres: 0 = parallel to pedestal base, 90 = perpendicular"));
    elevVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Float(MISSING_FLOAT)));
    elevVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialElevation.toString()));

    // add azimuth coordinate variable
    String aziCoordName = "azimuth" + abbrev;
    Variable aziVar = new Variable(ncfile, null, null, aziCoordName);
    aziVar.setDataType(DataType.FLOAT);
    aziVar.setDimensions(dim2);
    ncfile.addVariable(null, aziVar);

    aziVar.addAttribute(new Attribute(CDM.UNITS, "degrees"));
    aziVar.addAttribute(
        new Attribute(CDM.LONG_NAME, "azimuth angle in degrees: 0 = true north, 90 = east"));
    aziVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Float(MISSING_FLOAT)));
    aziVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialAzimuth.toString()));

    // add gate coordinate variable
    String gateCoordName = "distance" + abbrev;
    Variable gateVar = new Variable(ncfile, null, null, gateCoordName);
    gateVar.setDataType(DataType.FLOAT);
    gateVar.setDimensions(gateDimName);
    Array data =
        Array.makeArray(
            DataType.FLOAT,
            ngates,
            (double) firstRecord.getGateStart(datatype),
            (double) firstRecord.getGateSize(datatype));
    gateVar.setCachedData(data, false);
    ncfile.addVariable(null, gateVar);
    radarRadius = firstRecord.getGateStart(datatype) + ngates * firstRecord.getGateSize(datatype);

    gateVar.addAttribute(new Attribute(CDM.UNITS, "m"));
    gateVar.addAttribute(new Attribute(CDM.LONG_NAME, "radial distance to start of gate"));
    gateVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialDistance.toString()));

    // add number of radials variable
    String nradialsName = "numRadials" + abbrev;
    Variable nradialsVar = new Variable(ncfile, null, null, nradialsName);
    nradialsVar.setDataType(DataType.INT);
    nradialsVar.setDimensions(scanDim.getName());
    nradialsVar.addAttribute(new Attribute(CDM.LONG_NAME, "number of valid radials in this scan"));
    ncfile.addVariable(null, nradialsVar);

    // add number of gates variable
    String ngateName = "numGates" + abbrev;
    Variable ngateVar = new Variable(ncfile, null, null, ngateName);
    ngateVar.setDataType(DataType.INT);
    ngateVar.setDimensions(scanDim.getName());
    ngateVar.addAttribute(new Attribute(CDM.LONG_NAME, "number of valid gates in this scan"));
    ncfile.addVariable(null, ngateVar);

    makeCoordinateDataWithMissing(
        datatype, timeVar, elevVar, aziVar, nradialsVar, ngateVar, groups);

    // back to the data variable
    String coordinates =
        timeCoordName + " " + elevCoordName + " " + aziCoordName + " " + gateCoordName;
    v.addAttribute(new Attribute(_Coordinate.Axes, coordinates));

    // make the record map
    int nradials = radialDim.getLength();
    Cinrad2Record[][] map = new Cinrad2Record[nscans][nradials];
    for (int i = 0; i < groups.size(); i++) {
      Cinrad2Record[] mapScan = map[i];
      List group = (List) groups.get(i);
      for (int j = 0; j < group.size(); j++) {
        Cinrad2Record r = (Cinrad2Record) group.get(j);
        int radial = r.radial_num - 1;
        mapScan[radial] = r;
      }
    }

    Vgroup vg = new Vgroup(datatype, map);
    v.setSPobject(vg);

    return v;
  }
  public void open(RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask)
      throws IOException {
    NexradStationDB.init();

    volScan = new Cinrad2VolumeScan(raf, cancelTask);
    if (volScan.hasDifferentDopplarResolutions())
      throw new IllegalStateException("volScan.hasDifferentDopplarResolutions");

    radialDim = new Dimension("radial", volScan.getMaxRadials());
    ncfile.addDimension(null, radialDim);

    makeVariable(
        ncfile,
        Cinrad2Record.REFLECTIVITY,
        "Reflectivity",
        "Reflectivity",
        "R",
        volScan.getReflectivityGroups());
    int velocity_type =
        (volScan.getDopplarResolution() == Cinrad2Record.DOPPLER_RESOLUTION_HIGH_CODE)
            ? Cinrad2Record.VELOCITY_HI
            : Cinrad2Record.VELOCITY_LOW;
    Variable v =
        makeVariable(
            ncfile,
            velocity_type,
            "RadialVelocity",
            "Radial Velocity",
            "V",
            volScan.getVelocityGroups());
    makeVariableNoCoords(
        ncfile, Cinrad2Record.SPECTRUM_WIDTH, "SpectrumWidth", "Spectrum Width", v);

    if (volScan.getStationId() != null) {
      ncfile.addAttribute(null, new Attribute("Station", volScan.getStationId()));
      ncfile.addAttribute(null, new Attribute("StationName", volScan.getStationName()));
      ncfile.addAttribute(
          null, new Attribute("StationLatitude", new Double(volScan.getStationLatitude())));
      ncfile.addAttribute(
          null, new Attribute("StationLongitude", new Double(volScan.getStationLongitude())));
      ncfile.addAttribute(
          null,
          new Attribute("StationElevationInMeters", new Double(volScan.getStationElevation())));

      double latRadiusDegrees = Math.toDegrees(radarRadius / ucar.unidata.geoloc.Earth.getRadius());
      ncfile.addAttribute(
          null,
          new Attribute(
              "geospatial_lat_min", new Double(volScan.getStationLatitude() - latRadiusDegrees)));
      ncfile.addAttribute(
          null,
          new Attribute(
              "geospatial_lat_max", new Double(volScan.getStationLatitude() + latRadiusDegrees)));
      double cosLat = Math.cos(Math.toRadians(volScan.getStationLatitude()));
      double lonRadiusDegrees =
          Math.toDegrees(radarRadius / cosLat / ucar.unidata.geoloc.Earth.getRadius());
      ncfile.addAttribute(
          null,
          new Attribute(
              "geospatial_lon_min", new Double(volScan.getStationLongitude() - lonRadiusDegrees)));
      ncfile.addAttribute(
          null,
          new Attribute(
              "geospatial_lon_max", new Double(volScan.getStationLongitude() + lonRadiusDegrees)));

      // add a radial coordinate transform (experimental)
      Variable ct = new Variable(ncfile, null, null, "radialCoordinateTransform");
      ct.setDataType(DataType.CHAR);
      ct.setDimensions(""); // scalar
      ct.addAttribute(new Attribute("transform_name", "Radial"));
      ct.addAttribute(new Attribute("center_latitude", new Double(volScan.getStationLatitude())));
      ct.addAttribute(new Attribute("center_longitude", new Double(volScan.getStationLongitude())));
      ct.addAttribute(new Attribute("center_elevation", new Double(volScan.getStationElevation())));
      ct.addAttribute(new Attribute(_Coordinate.TransformType, "Radial"));
      ct.addAttribute(
          new Attribute(_Coordinate.AxisTypes, "RadialElevation RadialAzimuth RadialDistance"));

      Array data =
          Array.factory(DataType.CHAR.getPrimitiveClassType(), new int[0], new char[] {' '});
      ct.setCachedData(data, true);
      ncfile.addVariable(null, ct);
    }

    DateFormatter formatter = new DateFormatter();

    ncfile.addAttribute(null, new Attribute(CDM.CONVENTIONS, _Coordinate.Convention));
    ncfile.addAttribute(null, new Attribute("format", volScan.getDataFormat()));
    ncfile.addAttribute(null, new Attribute(CF.FEATURE_TYPE, FeatureType.RADIAL.toString()));
    // Date d = Cinrad2Record.getDate(volScan.getTitleJulianDays(), volScan.getTitleMsecs());
    // ncfile.addAttribute(null, new Attribute("base_date", formatter.toDateOnlyString(d)));

    ncfile.addAttribute(
        null,
        new Attribute(
            "time_coverage_start", formatter.toDateTimeStringISO(volScan.getStartDate())));
    ; // .toDateTimeStringISO(d)));
    ncfile.addAttribute(
        null,
        new Attribute("time_coverage_end", formatter.toDateTimeStringISO(volScan.getEndDate())));

    ncfile.addAttribute(
        null,
        new Attribute(CDM.HISTORY, "Direct read of Nexrad Level 2 file into NetCDF-Java 2.2 API"));
    ncfile.addAttribute(null, new Attribute("DataType", "Radial"));

    ncfile.addAttribute(
        null,
        new Attribute(
            "Title",
            "Nexrad Level 2 Station "
                + volScan.getStationId()
                + " from "
                + formatter.toDateTimeStringISO(volScan.getStartDate())
                + " to "
                + formatter.toDateTimeStringISO(volScan.getEndDate())));

    ncfile.addAttribute(
        null,
        new Attribute(
            "Summary",
            "Weather Surveillance Radar-1988 Doppler (WSR-88D) "
                + "Level II data are the three meteorological base data quantities: reflectivity, mean radial velocity, and "
                + "spectrum width."));

    ncfile.addAttribute(
        null,
        new Attribute(
            "keywords",
            "WSR-88D; NEXRAD; Radar Level II; reflectivity; mean radial velocity; spectrum width"));

    ncfile.addAttribute(
        null,
        new Attribute(
            "VolumeCoveragePatternName",
            Cinrad2Record.getVolumeCoveragePatternName(volScan.getVCP())));
    ncfile.addAttribute(
        null, new Attribute("VolumeCoveragePattern", new Integer(volScan.getVCP())));
    ncfile.addAttribute(
        null,
        new Attribute(
            "HorizonatalBeamWidthInDegrees", new Double(Cinrad2Record.HORIZONTAL_BEAM_WIDTH)));

    ncfile.finish();
  }
  public static NetcdfDataset buildStation(IObservationGroup obsGroup) {
    if (obsGroup.getDepths().length > 1) {
      return buildStationProfile(obsGroup);
    }
    NetcdfDataset ncds = null;
    File temp = null;
    try {
      /* Instantiate an empty NetcdfDataset object from the template ncml */
      temp = File.createTempFile("ooi", ".ncml");
      ncds = getNcdsFromTemplate(temp, "station.ncml");

      Map<String, String> allAttributes = new HashMap<String, String>();
      allAttributes.putAll(obsGroup.getAttributes());

      /* Do the station Id */
      ArrayInt.D0 aid = new ArrayInt.D0();
      aid.set(obsGroup.getId());
      ncds.findVariable("stnId").setCachedData(aid);

      /* Do the times */
      Number[] times = obsGroup.getTimes();
      IObservationGroup.DataType tdt = obsGroup.getTimeDataType();
      ncds.findDimension("time").setLength(times.length);
      Variable tvar = ncds.findVariable("time");
      tvar.setDataType(getNcDataType(tdt));
      tvar.setCachedData(getNcArray(times, tdt));

      /* Do the lat & lon */
      IObservationGroup.DataType lldt = obsGroup.getLatLonDataType();
      DataType ncdtLl = getNcDataType(lldt);
      Variable laVar = ncds.findVariable("lat");
      laVar.setDataType(ncdtLl);
      laVar.setCachedData(getNcScalar(obsGroup.getLat(), lldt));
      Variable loVar = ncds.findVariable("lon");
      loVar.setDataType(ncdtLl);
      loVar.setCachedData(getNcScalar(obsGroup.getLon(), lldt));

      /* Do the depth */
      IObservationGroup.DataType ddt = obsGroup.getDepthDataType();
      VariableDS zVar =
          new VariableDS(
              ncds, null, null, "stnDepth", getNcDataType(ddt), "", "m", "station depth");
      zVar.addAttribute(new Attribute("positive", "down"));
      ncds.addVariable(null, zVar);
      Number depth = obsGroup.getDepths()[0];
      zVar.setCachedData(getNcScalar(obsGroup.getDepths()[0], ddt));

      /* Do the data variables */
      for (VariableParams dn : obsGroup.getDataNames()) {
        DataType ncdtData = getNcDataType(dn.getDataType());
        VariableDS dvar =
            new VariableDS(
                ncds,
                null,
                null,
                dn.getShortName(),
                ncdtData,
                "time",
                dn.getUnits(),
                dn.getDescription());
        dvar.addAttribute(new Attribute(CF.COORDINATES, "time lon lat"));
        dvar.addAttribute(new Attribute(CF.STANDARD_NAME, dn.getStandardName()));
        Array adata = Array.factory(ncdtData, new int[] {times.length});
        IndexIterator aii = adata.getIndexIterator();
        dvar.setCachedData(adata);
        ncds.addVariable(null, dvar);

        for (int ti = 0; ti < times.length; ti++) {
          putArrayData(aii, ncdtData, obsGroup.getData(dn, times[ti], depth));
        }
      }

      /* Add global attributes */
      for (String key : allAttributes.keySet()) {
        ncds.addAttribute(null, new Attribute(key, allAttributes.get(key)));
      }

    } catch (FileNotFoundException ex) {
      Logger.getLogger(NcdsFactory.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
      Logger.getLogger(NcdsFactory.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
      if (temp != null) {
        if (!temp.delete()) {
          temp.deleteOnExit();
        }
      }
      if (ncds != null) {
        ncds.finish();
      }
    }

    return ncds;
  }
  public static NetcdfDataset buildTrajectory(List<IObservationGroup> obsGroups) {
    //        IObservationGroup.DataType tdt = IObservationGroup.DataType.values()[0];
    //        IObservationGroup.DataType lldt = IObservationGroup.DataType.values()[0];
    //        IObservationGroup.DataType ddt = IObservationGroup.DataType.values()[0];
    //        for(IObservationGroup og : obsGroups) {
    //            tdt = (og.getTimeDataType().compareTo(tdt) > 0) ? og.getTimeDataType() : tdt;
    //            lldt = (og.getLatLonDataType().compareTo(lldt) > 0) ? og.getLatLonDataType() :
    // lldt;
    //            ddt = (og.getDepthDataType().compareTo(ddt) > 0) ? og.getDepthDataType() : ddt;
    //        }

    NetcdfDataset ncds = null;
    File temp = null;
    try {
      /* Instantiate an empty NetcdfDataset object from the template ncml */
      temp = File.createTempFile("ooi", ".ncml");
      ncds = getNcdsFromTemplate(temp, "trajectory.ncml");

      int nobs = obsGroups.size();
      List<Number> allDepths = new ArrayList<Number>();
      List<VariableParams> allDn = new ArrayList<VariableParams>();
      int nt = nobs;
      int nd = 0;
      for (IObservationGroup og : obsGroups) {
        nd = Math.max(nd, og.getDepths().length);
        for (Number d : og.getDepths()) {
          if (!allDepths.contains(d)) {
            allDepths.add(d);
          }
        }
        for (VariableParams dn : og.getDataNames()) {
          if (!allDn.contains(dn)) {
            allDn.add(dn);
          }
        }
      }

      /* Do the trajectory ID */

      /* Do the times */
      Number[] times = obsGroups.get(0).getTimes();
      IObservationGroup.DataType tdt = obsGroups.get(0).getTimeDataType();
      DataType ncdtTime = getNcDataType(tdt);
      ncds.findDimension("time").setLength(nt);
      Array tarr = Array.factory(ncdtTime, new int[] {nt});
      IndexIterator tii = tarr.getIndexIterator();
      Variable tvar = ncds.findVariable("time");
      tvar.setDataType(getNcDataType(tdt));
      tvar.setCachedData(tarr);

      /* Do the lats */
      IObservationGroup.DataType lldt = obsGroups.get(0).getLatLonDataType();
      DataType ncdtLl = getNcDataType(lldt);
      Array laarr = Array.factory(ncdtLl, new int[] {nt});
      IndexIterator laii = laarr.getIndexIterator();
      Variable lavar = ncds.findVariable("lat");
      lavar.setDataType(ncdtLl);
      lavar.setCachedData(laarr);

      /* Do the lons */
      Array loarr = Array.factory(ncdtLl, new int[] {nt});
      IndexIterator loii = loarr.getIndexIterator();
      Variable lovar = ncds.findVariable("lon");
      lovar.setDataType(ncdtLl);
      lovar.setCachedData(loarr);

      /* Iterate over the observation groups and fill the data */
      Map<String, String> allAttributes = new HashMap<String, String>();
      IObservationGroup og;
      HashMap<String, IndexIterator> darrs = new HashMap<String, IndexIterator>();
      Number time;
      Number depth = allDepths.get(0);
      for (int obs = 0; obs < nobs; obs++) {
        og = obsGroups.get(obs);
        time = og.getTimes()[0];
        putArrayData(tii, ncdtTime, time);
        putArrayData(loii, ncdtLl, og.getLon());
        putArrayData(laii, ncdtLl, og.getLat());

        for (VariableParams dn : allDn) {
          if (og.getDataNames().contains(dn)) {
            DataType ncdtData = getNcDataType(dn.getDataType());
            VariableDS dvar = (VariableDS) ncds.findVariable(dn.getShortName());
            if (dvar == null) {
              dvar =
                  new VariableDS(
                      ncds,
                      null,
                      null,
                      dn.getShortName(),
                      ncdtData,
                      "time",
                      dn.getUnits(),
                      dn.getDescription());
              dvar.addAttribute(new Attribute(CF.COORDINATES, "time lon lat"));
              //                            dvar.addAttribute(new Attribute("missing_value",
              // missingData));
              dvar.addAttribute(new Attribute(CF.STANDARD_NAME, dn.getStandardName()));
              Array darr = Array.factory(ncdtData, new int[] {nt});
              dvar.setCachedData(darr);

              darrs.put(dn.getStandardName(), darr.getIndexIterator());
              ncds.addVariable(null, dvar);
            }
            putArrayData(darrs.get(dn.getStandardName()), ncdtData, og.getData(dn, time, depth));

          } else {
            /*
             * station doesn't have this variable - don't believe
             * this can even happen...
             *
             * NOTE: This would indicate a problem with the above processing where the data-name list
             * has been modified prior to contains-checking
             */
          }
        }
      }

      /* Add global attributes */
      for (String key : allAttributes.keySet()) {
        ncds.addAttribute(null, new Attribute(key, allAttributes.get(key)));
      }
    } catch (FileNotFoundException ex) {
      Logger.getLogger(NcdsFactory.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
      Logger.getLogger(NcdsFactory.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
      if (temp != null) {
        if (!temp.delete()) {
          temp.deleteOnExit();
        }
      }
      if (ncds != null) {
        ncds.finish();
      }
    }

    return ncds;
  }