Package ucar.nc2.dt.fmrc

Source Code of ucar.nc2.dt.fmrc.FmrcDefinition$VertTimeCoord

/*
* Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation.  Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/

package ucar.nc2.dt.fmrc;

import org.jdom.output.XMLOutputter;
import org.jdom.output.Format;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.*;
import java.util.*;

import ucar.nc2.dataset.CoordinateAxis1D;
import ucar.unidata.util.StringUtil;

/**
* Defines the expected inventory of a Forecast Model Run Collection.
* <p/>
* <pre>
* Data Structures
* <p/>
*  List VertTimeCoord
*    double[] values
* <p/>
*  List TimeCoord
*    double[] offsetHour
* <p/>
*  List RunSeq
*    List Run - runHour dependent TimeCoord
*      double hour
*      TimeCoord
* <p/>
*    List Grid
*     String name
*     VertTimeCoord - time dependent vertical coordinate
*       VertCoord
*       TimeCoord (optional)
* <p/>
* <p/>
* Abstractly, the data is a table:
*   Run  Grid  TimeCoord  VertCoord
*   Run  Grid  TimeCoord  VertCoord
*   Run  Grid  TimeCoord  VertCoord
*   ...
* <p/>
* We will use the notation ({} means list)
*  {Run, Grid, TimeCoord, VertCoord}
* <p/>
* The simplest case would be if all runs have the same grids, which all use the same time coord, and each grid always
*  uses the same vert coord :
* (1) {runTime} X {Grid, VertCoord} X TimeCoord      (X means product)
* <p/>
* The usual case is that there are multiple TimeCoords, but a grid always uses the same one:
* (2) {runTime} X {Grid, VertCoord, TimeCoord}
* <p/>
* Since all runTimes are the same, the definition only need be:
* (2d) {Grid, VertCoord, TimeCoord}
* <p/>
* Another case is that different run hours use different TimeCoords. We will call this a RunSeq, and we associate with each
* RunSeq the list of grids that use it:
*   Run = runHour, TimeCoord
*   RunSeq = {runHour, TimeCoord} X {Grid, VertCoord}
* <p/>
* Different grids use different RunSeqs, so we have a list of RunSeq:
* (3d) {{runHour, TimeCoord} X {Grid, VertCoord}}
* <p/>
* We can recast (2d), when all runHours are the same,  as:
* (2d') {TimeCoord X {Grid, VertCoord}}
* which means that we are grouping grids by unique TimeCoord. (1d) would be the case where there is only one in the list.
* <p/>
* Another case is when the VertCoord depends on the TimeCoord, but all run hours are the same:
* (4d) {TimeCoord X {Grid, VertCoord(TimeCoord)}}
* <p/>
* Which lead us to generalize a VertCoord to a time-dependent one, called VertTimeCoord.
* <p/>
* The most general case is then
*   {{runHour, TimeCoord} X {Grid, VertTimeCoord}}
* <p/>
* </pre>
*
* @author caron
*/
public class FmrcDefinition implements ucar.nc2.dt.fmr.FmrcCoordSys {
  static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FmrcDefinition.class);

  ///////////////////////////////////////////////////////////////////

  private List<VertTimeCoord> vertTimeCoords;
  private List<ForecastModelRunInventory.TimeCoord> timeCoords;
  private List<ForecastModelRunInventory.EnsCoord> ensCoords;
  private List<RunSeq> runSequences;

  private String name;
  private String suffixFilter;

  public FmrcDefinition() {
    cal.setTimeZone(TimeZone.getTimeZone("UTC"));
  }

  public String getSuffixFilter() {
    return suffixFilter;
  }

  public List<RunSeq> getRunSequences() {
    return runSequences;
  }

  public boolean hasVariable(String searchName) {
    return findGridByName(searchName) != null;
  }

  public ucar.nc2.dt.fmr.FmrcCoordSys.VertCoord findVertCoordForVariable(String searchName) {
    Grid grid = findGridByName(searchName);
    return (grid.vtc == null) ? null : grid.vtc.vc;
  }

  public ucar.nc2.dt.fmr.FmrcCoordSys.TimeCoord findTimeCoordForVariable(String searchName, java.util.Date runTime) {
    for (RunSeq runSeq : runSequences) {
      Grid grid = runSeq.findGrid(searchName);
      if (null != grid) {
        ForecastModelRunInventory.TimeCoord from = runSeq.findTimeCoordByRuntime(runTime);
        // we need to wrap it, giving it the name of the RunSeq
        return new ForecastModelRunInventory.TimeCoord(runSeq.num, from);
      }
    }
    return null;
  }

  private ForecastModelRunInventory.TimeCoord findTimeCoord(String id) {
    for (ForecastModelRunInventory.TimeCoord tc : timeCoords) {
      if (tc.getId().equals(id))
        return tc;
    }
    return null;
  }

  ///////////////////////////////////////////////////////////////////////////////////////////////

  // encapsolates a Grid and its vertical coordinate, which may be time-dependent

  public static class Grid implements Comparable {
    private String name; // , searchName;
    private VertTimeCoord vtc = null;
    private ForecastModelRunInventory.EnsCoord ec = null;

    Grid(String name) {
      this.name = name;
    }

    public EnsCoord getEnsTimeCoord() {
      return ec;
    }

    //public String getName() { return name; }
    //public void setName(String name) { this.name = name; }

    public VertTimeCoord getVertTimeCoord() {
      return vtc;
    }

    public int countVertCoords(double offsetHour) {
      return (vtc == null) ? 1 : vtc.countVertCoords(offsetHour);
    }

    /**
     * Get inventory as an array of vert coords, at a particular time coord = hourOffset
     *
     * @param hourOffset : may or may not be in the list of time coords
     * @return array of vert coords. NaN = missing; -0.0 = surface.
     */
    public double[] getVertCoords(double hourOffset) {

      if (vtc == null) {
        double[] result = new double[1]; // if 2D return -0.0
        result[0] = -0.0;
        return result;
      }

      return vtc.getVertCoords(hourOffset);
    }

    public int compareTo(Object o) {
      Grid other = (Grid) o;
      return name.compareTo(other.name);
    }
  }

  class Run {
    double runHour; // hour since 00:00
    ForecastModelRunInventory.TimeCoord tc;

    Run(ForecastModelRunInventory.TimeCoord tc, double runHour) {
      this.tc = tc;
      this.runHour = runHour;
    }
  }

  // A sequence of Runs.
  // each RunSeq is a unique time coordinate
  private int runseq_num = 0;

  public class RunSeq {
    private boolean isAll = false;    // true if they all use the same OffsetHours
    private ForecastModelRunInventory.TimeCoord allUseOffset; // they all use this one
    private List<Run> runs = new ArrayList<Run>(); // list of Run
    private List<Grid> vars = new ArrayList<Grid>(); // list of Grid
    private int num = 0;

    RunSeq(String id) {
      this.isAll = true;
      this.allUseOffset = findTimeCoord(id);
      num = runseq_num++;
    }

    RunSeq(List<Run> runs) {
      this.runs = runs;
      num = runseq_num++;

      // complete a 24 hour cycle
      int matchIndex = 0;
      Run last = runs.get(runs.size() - 1);
      double runHour = last.runHour;
      while (runHour < 24.0) {
        Run match = runs.get(matchIndex);
        Run next = runs.get(matchIndex + 1);
        double incr = next.runHour - match.runHour;
        if (incr <= 0)
          break;
        runHour += incr;
        runs.add(new Run(next.tc, runHour));
        matchIndex++;
      }
    }

    public String getName() {
      return (num == 0) ? "time" : "time" + num;
    }

    /**
     * Find the TimeCoord the should be used for this runTime
     *
     * @param runTime run date
     * @return TimeCoord, or null if no match.
     */
    public ForecastModelRunInventory.TimeCoord findTimeCoordByRuntime(Date runTime) {
      if (isAll)
        return allUseOffset;
      double hour = getHour(runTime);
      Run run = findRun(hour);
      if (run == null) return null;
      return run.tc;
    }

    /**
     * @param hour run hour
     * @return the Run that matches the run hour
     */
    Run findRun(double hour) {
      for (Run run : runs) {
        if (run.runHour == hour) return run;
      }
      return null;
    }

    public Grid findGrid(String name) {
      if (name == null) return null;

      for (Grid grid : vars) {
        if (name.equals(grid.name))
          return grid;
      }

      return null;
    }

  } // RunSeq

  public RunSeq findSeqForVariable(String name) {
    for (RunSeq runSeq : runSequences) {
      if (runSeq.findGrid(name) != null)
        return runSeq;
    }
    return null;
  }

  Grid findGridByName(String name) {
    for (RunSeq runSeq : runSequences) {
      Grid grid = runSeq.findGrid(name);
      if (null != grid)
        return grid;
    }
    return null;
  }

  VertTimeCoord findVertCoord(String id) {
    if (id == null)
      return null;

    for (VertTimeCoord vc : vertTimeCoords) {
      if (vc.getId().equals(id))
        return vc;
    }
    return null;
  }

  VertTimeCoord findVertCoordByName(String name) {
    for (VertTimeCoord vc : vertTimeCoords) {
      if (vc.getName().equals(name))
        return vc;
    }
    return null;
  }

  boolean replaceVertCoord(ForecastModelRunInventory.VertCoord vc) {
    for (VertTimeCoord vtc : vertTimeCoords) {
      if (vtc.getName().equals(vc.getName())) {
        vtc.vc.values1 = vc.values1;
        vtc.vc.values2 = vc.values2;
        vtc.vc.setId(vc.getId());
        vtc.vc.setUnits(vc.getUnits());
        return true;
      }
    }

    // make a new one
    vertTimeCoords.add(new VertTimeCoord(vc));
    return false;
  }


  ///////////////////////////////////////////////////////////////////////////////////////////////

  /* vertical coordinates that depend on the offset hour */

  class VertTimeCoord implements Comparable {
    ForecastModelRunInventory.VertCoord vc;
    ForecastModelRunInventory.TimeCoord tc; // optional
    int ntimes, nverts;
    double[][] vcForTimeIndex;  // vcForTimeIndex[ntimes]
    List<String> restrictList;

    VertTimeCoord(ForecastModelRunInventory.VertCoord vc) {
      this.vc = vc;
      ntimes = (tc == null) ? 1 : tc.getOffsetHours().length;
      nverts = vc.getValues1().length;
    }

    VertTimeCoord(ForecastModelRunInventory.VertCoord vc, RunSeq runSeq) {
      if (runSeq.isAll) {
        this.tc = runSeq.allUseOffset;
      } else {
        // make union timeCoord
        Set<Double> valueSet = new HashSet<Double>();
        for (Run run : runSeq.runs) {
          addValues(valueSet, run.tc.getOffsetHours());
        }
        List<Double> valueList = Arrays.asList((Double[]) valueSet.toArray(new Double[valueSet.size()]));
        Collections.sort(valueList);
        double[] values = new double[valueList.size()];
        for (int i = 0; i < valueList.size(); i++) {
          values[i] = valueList.get(i);
        }
        this.tc = new ForecastModelRunInventory.TimeCoord();
        this.tc.setOffsetHours(values);
        this.tc.setId("union");
      }

      this.vc = vc;

      ntimes = (tc == null) ? 1 : tc.getOffsetHours().length;
      nverts = vc.getValues1().length;
    }

    private void addValues(Set<Double> valueSet, double[] values) {
      for (double value : values) valueSet.add(value);
    }

    String getId() {
      return vc.getId();
    }

    String getName() {
      return vc.getName();
    }
    //double[] getValues() { return vc.getValues(); }

    void addRestriction(String vertCoordsString, String timeCoords) {
      StringTokenizer stoker = new StringTokenizer(vertCoordsString, " ,");
      int n = stoker.countTokens();
      double[] vertCoords = new double[n];
      int count = 0;
      while (stoker.hasMoreTokens()) {
        vertCoords[count++] = Double.parseDouble(stoker.nextToken());
      }

      if (vcForTimeIndex == null) {
        restrictList = new ArrayList<String>();
        vcForTimeIndex = new double[ntimes][];
        for (int i = 0; i < vcForTimeIndex.length; i++) {
          vcForTimeIndex[i] = vc.getValues1(); // LOOK WRONG
        }
      }

      // save these in case we have to write them back out
      restrictList.add(vertCoordsString);
      restrictList.add(timeCoords);

      stoker = new StringTokenizer(timeCoords, " ,");
      while (stoker.hasMoreTokens()) {
        double hour = Double.parseDouble(stoker.nextToken());
        int index = tc.findIndex(hour);
        if (index < 0)
          log.error("hour Offset" + hour + " not found in TimeCoord " + tc.getId());
        vcForTimeIndex[index] = vertCoords;
      }
    }

    double[] getVertCoords(double offsetHour) {
      if ((tc == null) || (null == vcForTimeIndex))
        return vc.getValues1(); // LOOK WRONG

      int index = tc.findIndex(offsetHour);
      if (index < 0)
        return new double[0];

      return vcForTimeIndex[index];
    }

    int countVertCoords(double offsetHour) {
      if ((tc == null) || (null == vcForTimeIndex))
        return vc.getValues1().length;

      int index = tc.findIndex(offsetHour);
      if (index < 0)
        return 0;

      return vcForTimeIndex[index].length;
    }

    public int compareTo(Object o) {
      VertTimeCoord other = (VertTimeCoord) o;
      return getName().compareTo(other.getName());
    }
  }

  private ForecastModelRunInventory.EnsCoord findEnsCoord(String id) {
    if (id == null)
      return null;

    for (ForecastModelRunInventory.EnsCoord ec : ensCoords) {
      if (ec.getId().equals(id))
        return ec;
    }
    return null;
  }

  //////////////////////////////////////////////////////////////////////////////////

  public String writeDefinitionXML() {
    XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
    return fmt.outputString(makeDefinitionXML());
  }

  public void writeDefinitionXML(OutputStream os) throws IOException {
    XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
    fmt.output(makeDefinitionXML(), os);
  }

  /**
   * Create an XML document for the entire collection
   *
   * @return an XML document for the entire collection
   */
  public Document makeDefinitionXML() {
    Element rootElem = new Element("fmrcDefinition");
    Document doc = new Document(rootElem);
    if (name != null)
      rootElem.setAttribute("dataset", name);
    if (null != suffixFilter)
      rootElem.setAttribute("suffixFilter", suffixFilter);

    // list all the ensemble coordinaates
    Collections.sort(ensCoords);
    for (ForecastModelRunInventory.EnsCoord ec : ensCoords) {
      Element ecElem = new Element("ensCoord");
      rootElem.addContent(ecElem);
      ecElem.setAttribute("id", ec.getId());
      ecElem.setAttribute("name", ec.getName());
      ecElem.setAttribute("product_definition", Integer.toString(ec.getPDN()));

      StringBuilder sbuff = new StringBuilder();
      int[] ensTypes = ec.getEnsTypes(); //new int[ ec.getNEnsembles() ];
      for (int j = 0; j < ensTypes.length; j++) {
        if (j > 0) sbuff.append(" ");
        sbuff.append(Integer.toString(ensTypes[j]));

      }
      ecElem.addContent(sbuff.toString());
    }

    // list all the vertical coordinaates
    Collections.sort(vertTimeCoords);
    for (VertTimeCoord vtc : vertTimeCoords) {
      ForecastModelRunInventory.VertCoord vc = vtc.vc;

      Element vcElem = new Element("vertCoord");
      rootElem.addContent(vcElem);
      vcElem.setAttribute("id", vc.getId());
      vcElem.setAttribute("name", vc.getName());
      if (null != vc.getUnits())
        vcElem.setAttribute("units", vc.getUnits());

      StringBuilder sbuff = new StringBuilder();
      double[] values1 = vc.getValues1();
      double[] values2 = vc.getValues2();

      for (int j = 0; j < values1.length; j++) {
        if (j > 0) sbuff.append(" ");
        sbuff.append(Double.toString(values1[j]));
        if (values2 != null) {
          sbuff.append(",");
          sbuff.append(Double.toString(values2[j]));
        }
      }
      vcElem.addContent(sbuff.toString());
    }

    // list all the offset hours
    Collections.sort(timeCoords);
    for (ForecastModelRunInventory.TimeCoord tc : timeCoords) {
      Element offsetElem = new Element("offsetHours");
      rootElem.addContent(offsetElem);
      offsetElem.setAttribute("id", tc.getId());

      StringBuilder sbuff = new StringBuilder();
      double[] offset = tc.getOffsetHours();
      for (int j = 0; j < offset.length; j++) {
        if (j > 0) sbuff.append(" ");
        sbuff.append(Double.toString(offset[j]));
      }
      offsetElem.addContent(sbuff.toString());
    }

    // list all the time sequences, containing variables
    for (RunSeq runSeq : runSequences) {
      Element seqElem = new Element("runSequence");
      rootElem.addContent(seqElem);

      if (runSeq.isAll) {
        seqElem.setAttribute("allUseSeq", runSeq.allUseOffset.getId());

      } else { // otherwise show each run
        for (Run run : runSeq.runs) {
          Element runElem = new Element("run");
          seqElem.addContent(runElem);

          runElem.setAttribute("runHour", Double.toString(run.runHour));
          runElem.setAttribute("offsetHourSeq", run.tc.getId());
        }
      }

      for (Grid grid : runSeq.vars) {
        Element varElem = new Element("variable");
        seqElem.addContent(varElem);
        varElem.setAttribute("name", grid.name);
        if (grid.ec != null)
          varElem.setAttribute("ensCoord", grid.ec.getId());
        if (grid.vtc != null) {
          varElem.setAttribute("vertCoord", grid.vtc.getId());

          // look for time-dependent vert coordinates - always specific to one variable
          if (grid.vtc.restrictList != null) {
            Iterator iter = grid.vtc.restrictList.iterator();
            while (iter.hasNext()) {
              Element vtElem = new Element("vertCoord");
              varElem.addContent(vtElem);
              vtElem.setAttribute("restrict", (String) iter.next());
              vtElem.setText((String) iter.next());
            }
          }
        }
      }
    }
    return doc;
  }

  public boolean readDefinitionXML(String xmlLocation) throws IOException {
    File xml = new File(xmlLocation);
    if (!xml.exists()) return false;

    InputStream is = new BufferedInputStream(new FileInputStream(xmlLocation));
    org.jdom.Document doc;
    try {
      SAXBuilder builder = new SAXBuilder();
      doc = builder.build(is);
    } catch (JDOMException e) {
      throw new IOException(e.getMessage());
    }

    Element rootElem = doc.getRootElement();
    name = rootElem.getAttributeValue("name");
    suffixFilter = rootElem.getAttributeValue("suffixFilter");

    ensCoords = new ArrayList<ForecastModelRunInventory.EnsCoord>();
    java.util.List<Element> eList = rootElem.getChildren("ensCoord");
    for (Element ecElem : eList) {
      ForecastModelRunInventory.EnsCoord ec = new ForecastModelRunInventory.EnsCoord();
      ec.setId(ecElem.getAttributeValue("id"));
      ec.setName(ecElem.getAttributeValue("name"));
      ec.setPDN(Integer.parseInt(ecElem.getAttributeValue("product_definition")));

      // parse the values
      String values = ecElem.getText();
      StringTokenizer stoke = new StringTokenizer(values);
      int n = stoke.countTokens();
      ec.setNEnsembles(n);
      int[] ensType = new int[n];
      int count = 0;
      while (stoke.hasMoreTokens()) {
        String toke = stoke.nextToken();
        int pos = toke.indexOf(',');
        if (pos < 0)
          ensType[count] = Integer.parseInt(toke);
        count++;
      }
      ec.setEnsTypes(ensType);
      ensCoords.add(ec);
    }


    vertTimeCoords = new ArrayList<VertTimeCoord>();
    java.util.List<Element> vList = rootElem.getChildren("vertCoord");
    for (Element vcElem : vList) {
      ForecastModelRunInventory.VertCoord vc = new ForecastModelRunInventory.VertCoord();
      vc.setId(vcElem.getAttributeValue("id"));
      vc.setName(vcElem.getAttributeValue("name"));
      vc.setUnits(vcElem.getAttributeValue("units"));

      /* parse the values
      String values = vcElem.getText();
      StringTokenizer stoke = new StringTokenizer(values);
      int n = stoke.countTokens();
      double[] vals = new double[n];
      int count = 0;
      while (stoke.hasMoreTokens()) {
        vals[count++] = Double.parseDouble( stoke.nextToken());
      }
      vc.setValues( vals); */

      // parse the values
      String values = vcElem.getText();
      StringTokenizer stoke = new StringTokenizer(values);
      int n = stoke.countTokens();
      double[] values1 = new double[n];
      double[] values2 = null;
      int count = 0;
      while (stoke.hasMoreTokens()) {
        String toke = stoke.nextToken();
        int pos = toke.indexOf(',');
        if (pos < 0)
          values1[count] = Double.parseDouble(toke);
        else {
          if (values2 == null)
            values2 = new double[n];
          String val1 = toke.substring(0, pos);
          String val2 = toke.substring(pos + 1);
          values1[count] = Double.parseDouble(val1);
          values2[count] = Double.parseDouble(val2);
        }
        count++;
      }
      vc.setValues1(values1);
      if (values2 != null)
        vc.setValues2(values2);

      // wrap it as a VertTimeCoord
      VertTimeCoord vtc = new VertTimeCoord(vc);
      vertTimeCoords.add(vtc);
    }

    timeCoords = new ArrayList<ForecastModelRunInventory.TimeCoord>();
    java.util.List<Element> tList = rootElem.getChildren("offsetHours");
    for (Element timeElem : tList) {
      ForecastModelRunInventory.TimeCoord tc = new ForecastModelRunInventory.TimeCoord();
      timeCoords.add(tc);
      tc.setId(timeElem.getAttributeValue("id"));

      // parse the values
      String values = timeElem.getText();
      StringTokenizer stoke = new StringTokenizer(values);
      int n = stoke.countTokens();
      double[] offset = new double[n];
      int count = 0;
      while (stoke.hasMoreTokens()) {
        offset[count++] = Double.parseDouble(stoke.nextToken());
      }
      tc.setOffsetHours(offset);
    }

    runSequences = new ArrayList<RunSeq>();
    java.util.List<Element> runseqList = rootElem.getChildren("runSequence");
    for (Element runseqElem : runseqList) {
      RunSeq rseq;

      String allUseId = runseqElem.getAttributeValue("allUseSeq");
      if (allUseId != null) {
        rseq = new RunSeq(allUseId);
      } else {
        List<Run> runs = new ArrayList<Run>();
        List<Element> runList = runseqElem.getChildren("run");
        for (Element runElem : runList) {
          String id = runElem.getAttributeValue("offsetHourSeq");
          ForecastModelRunInventory.TimeCoord tc = findTimeCoord(id);
          String hour = runElem.getAttributeValue("runHour");

          Run run = new Run(tc, Double.parseDouble(hour));
          runs.add(run);
        }
        rseq = new RunSeq(runs);
      }

      runSequences.add(rseq);

      List<Element> varList = runseqElem.getChildren("variable");
      for (Element varElem : varList) {
        String name = varElem.getAttributeValue("name");
        Grid grid = new Grid(name);
        rseq.vars.add(grid);
        grid.ec = findEnsCoord(varElem.getAttributeValue("ensCoord"));
        //grid.ec = ForecastModelRunInventory.findEnsCoord(ensCoords, varElem.getAttributeValue("ensCoord"));
        grid.vtc = findVertCoord(varElem.getAttributeValue("vertCoord"));

        // look for time dependent vert coordinates - always specific to one variable
        List<Element> rList = varElem.getChildren("vertTimeCoord");
        // gotta be inside a useAllSeq runSeq
        if (rList.size() > 0) {
          grid.vtc = new VertTimeCoord(grid.vtc.vc, rseq);

          for (Element vtElem : rList) {
            String vertCoords = vtElem.getAttributeValue("restrict");
            String timeCoords = vtElem.getText();
            grid.vtc.addRestriction(vertCoords, timeCoords);
          }
        }
      }
      Collections.sort(rseq.vars);

    }

    return true;
  }

  //////////////////////////////////////////////////////////////////////

  public void makeFromCollectionInventory(FmrcInventory fmrc) {
    this.name = fmrc.getName();

    this.timeCoords = fmrc.getTimeCoords();
    this.ensCoords = fmrc.getEnsCoords();

    this.vertTimeCoords = new ArrayList<VertTimeCoord>();
    for (int i = 0; i < fmrc.getVertCoords().size(); i++) {
      ForecastModelRunInventory.VertCoord vc = fmrc.getVertCoords().get(i);
      vertTimeCoords.add(new VertTimeCoord(vc));
    }

    this.runSequences = new ArrayList<RunSeq>();

    // Convert the run sequences, containing variables
    List<FmrcInventory.RunSeq> seqs = fmrc.getRunSequences();
    for (FmrcInventory.RunSeq invSeq : seqs) {
      // check to see if all runs use the same tc
      boolean isAll = true;
      ForecastModelRunInventory.TimeCoord oneTc = null;
      for (int j = 0; j < invSeq.runs.size(); j++) {
        FmrcInventory.Run run = invSeq.runs.get(j);
        if (j == 0)
          oneTc = run.tc;
        else {
          if (oneTc != run.tc)
            isAll = false;
        }
      }

      RunSeq runSeq;
      if (isAll) {
        runSeq = new RunSeq(oneTc.getId());
      } else {
        List<Run> runs = new ArrayList<Run>();
        for (FmrcInventory.Run invRun : invSeq.runs) {
          Run run = new Run(invRun.tc, getHour(invRun.runTime));
          runs.add(run);
        }
        runSeq = new RunSeq(runs);
      }
      runSequences.add(runSeq);

      // convert UberGrids to Grid
      List<FmrcInventory.UberGrid> vars = invSeq.getVariables();
      for (FmrcInventory.UberGrid uv : vars) {
        Grid grid = new Grid(uv.getName());
        runSeq.vars.add(grid);
        if (uv.vertCoordUnion != null)
          grid.vtc = new VertTimeCoord(uv.vertCoordUnion);
        if (uv.ensCoordUnion != null)
          grid.ec = uv.ensCoordUnion;
      }
    }

    // sort vert coords
    Collections.sort(this.vertTimeCoords);

  }

  /**
   * Add just the vertical coord info to the definition
   *
   * @param fmrc the collection inventory
   */
  public void addVertCoordsFromCollectionInventory(FmrcInventory fmrc) {
    this.vertTimeCoords = new ArrayList<VertTimeCoord>();
    for (int i = 0; i < fmrc.getVertCoords().size(); i++) {
      ForecastModelRunInventory.VertCoord vc = fmrc.getVertCoords().get(i);
      vertTimeCoords.add(new VertTimeCoord(vc));
    }

    // Convert the run sequences, containing variables
    List<FmrcInventory.RunSeq> seqs = fmrc.getRunSequences();
    for (FmrcInventory.RunSeq invSeq : seqs) {
      // convert UberGrids to Grid
      List<FmrcInventory.UberGrid> vars = invSeq.getVariables();
      for (FmrcInventory.UberGrid uv : vars) {
        if (uv.vertCoordUnion != null) {
          String sname = uv.getName();
          Grid grid = findGridByName(sname);
          grid.vtc = new VertTimeCoord(uv.vertCoordUnion);
        }
      }
    }
  }

  //  utilities - move to fmrc ?
  private Calendar cal = new GregorianCalendar(); // for date computations

  private double getHour(Date d) {
    cal.setTime(d);
    int hour = cal.get(Calendar.HOUR_OF_DAY);
    double min = (double) cal.get(Calendar.MINUTE);
    return hour + min / 60;
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////
  // ad-hoc manipulations of the definitions

  // replace ids

  static void convertIds(String datasetName, String defName) throws IOException {
    System.out.println(datasetName);
    ForecastModelRunInventory fmrInv = ForecastModelRunInventory.open(null, datasetName, ForecastModelRunInventory.OPEN_FORCE_NEW, true);

    FmrcDefinition fmrDef = new FmrcDefinition();
    fmrDef.readDefinitionXML(defName);

    boolean changed = false;

    // make hashmap
    Map<String, Grid> hash = new HashMap<String, Grid>();
    for (RunSeq runSeq : fmrDef.runSequences) {
      for (Grid gridDef : runSeq.vars) {
        String munged = StringUtil.replace(gridDef.name, '_', "");
        hash.put(munged, gridDef);
      }
    }

    // make sure each grid in fmrInv is also in fmrDef
    List<ForecastModelRunInventory.TimeCoord> fmrInvTimeCoords = fmrInv.getTimeCoords();
    for (ForecastModelRunInventory.TimeCoord tc : fmrInvTimeCoords) {
      List<ForecastModelRunInventory.Grid> fmrInvGrids = tc.getGrids();
      for (ForecastModelRunInventory.Grid invGrid : fmrInvGrids) {
        Grid defGrid = fmrDef.findGridByName(invGrid.name);
        if (null == defGrid) {
          String munged = StringUtil.replace(invGrid.name, "-", "");
          munged = StringUtil.replace(munged, "_", "");
          Grid gridDefnew = hash.get(munged);
          if (gridDefnew != null) {
            System.out.println(" replace " + gridDefnew.name + " with " + invGrid.name);
            gridDefnew.name = invGrid.name;
            changed = false; // true;
          } else {
            System.out.println("*** cant find replacement for grid= " + invGrid.name + " in the definition");
          }
        }
      }
    }

    if (changed) {
      int pos = defName.lastIndexOf("/");
      String newDef = defName.substring(0, pos) + "/new/" + defName.substring(pos);
      FileOutputStream fout = new FileOutputStream(newDef);
      fmrDef.writeDefinitionXML(fout);
    }
  }

  static boolean showState = false;

  static void convert(String datasetName, String defName) throws IOException {
    System.out.println(datasetName);
    ForecastModelRunInventory fmrInv = ForecastModelRunInventory.open(null, datasetName, ForecastModelRunInventory.OPEN_FORCE_NEW, true);

    FmrcDefinition fmrDef = new FmrcDefinition();
    fmrDef.readDefinitionXML(defName);

    // replace vert coords
    List<ForecastModelRunInventory.VertCoord> vcList = fmrInv.getVertCoords();
    for (ForecastModelRunInventory.VertCoord vc : vcList) {
      CoordinateAxis1D axis = vc.axis;
      if (axis == null)
        System.out.println("*** No Axis " + vc.getName());
      else {
        // boolean isLayer = null != axis.findAttribute(_Coordinate.ZisLayer);
        //if (isLayer) {
        if (showState) System.out.print(" " + vc.getName() + " contig= " + axis.isContiguous());
        // see if theres any TimeCoord that use this
        //findGridsForVertCoord( fmrDef, vc);
        boolean ok = fmrDef.replaceVertCoord(vc);
        if (showState) System.out.println(" = " + ok);
        //}
      }
    }
    Collections.sort(fmrDef.vertTimeCoords);

    // reset vert id on grids
    for (RunSeq runSeq : fmrDef.runSequences) {
      for (Grid gridDef : runSeq.vars) {
        ForecastModelRunInventory.Grid gridInv = fmrInv.findGrid(gridDef.name);
        if (gridInv == null) {
          System.out.println("*** cant find def grid= " + gridDef.name + " in the inventory ");
          continue;
        }
        if (gridInv.vc != null) {
          VertTimeCoord new_vtc = fmrDef.findVertCoordByName(gridInv.vc.getName());
          if (new_vtc == null) {
            System.out.println("*** cant find VertCoord= " + gridInv.vc.getName());
            continue;
          }
          gridDef.vtc = new_vtc;
          if (showState) System.out.println(" ok= " + gridDef.name);
        }
      }
    }

    int pos = defName.lastIndexOf("/");
    String newDef = defName.substring(0, pos) + "/new/" + defName.substring(pos);
    FileOutputStream fout = new FileOutputStream(newDef);
    fmrDef.writeDefinitionXML(fout);

    // make sure each grid in fmrInv is also in fmrDef
    List<ForecastModelRunInventory.TimeCoord> fmrInvTimeCoords = fmrInv.getTimeCoords();
    for (ForecastModelRunInventory.TimeCoord tc : fmrInvTimeCoords) {
      List<ForecastModelRunInventory.Grid> fmrInvGrids = tc.getGrids();
      for (ForecastModelRunInventory.Grid invGrid : fmrInvGrids) {
        Grid defGrid = fmrDef.findGridByName(invGrid.name);
        if (null == defGrid)
          System.out.println("*** cant find inv grid= " + invGrid.name + " in the definition");
        else {
          ForecastModelRunInventory.VertCoord inv_vc = invGrid.vc;

          if ((inv_vc == null) && (defGrid.vtc == null)) continue; // ok
          if ((inv_vc != null) && (defGrid.vtc == null)) {
            System.out.println("*** mismatch " + invGrid.name + " VertCoord: inv= " + inv_vc.getSize() + ", no def ");
            continue;
          }

          if ((inv_vc == null) && (defGrid.vtc != null)) {
            ForecastModelRunInventory.VertCoord def_vc = defGrid.vtc.vc;
            System.out.println("*** mismatch " + invGrid.name + " VertCoord: def= " + def_vc.getSize() + ", no inv ");
            continue;
          }

          ForecastModelRunInventory.VertCoord def_vc = defGrid.vtc.vc;
          if (inv_vc.getSize() != def_vc.getSize()) {
            System.out.println("*** mismatch " + invGrid.name + " VertCoord size: inv= " + inv_vc.getSize() + ", def = " + def_vc.getSize());
          }
        }
      }

    }
  }

  static void showVertCoords(String datasetName, String defName) throws IOException {
    System.out.println("--------------------------------------");
    System.out.println(defName);
    FmrcDefinition fmrDef = new FmrcDefinition();
    fmrDef.readDefinitionXML(defName);

    /* List vtList = fmrDef.vertTimeCoords;
    for (int i = 0; i < vtList.size(); i++) {
      VertTimeCoord vtc = (VertTimeCoord) vtList.get(i);
      System.out.println(" "+vtc.getName());
    } */

    System.out.println(datasetName);
    ForecastModelRunInventory fmrInv = ForecastModelRunInventory.open(null, datasetName, ForecastModelRunInventory.OPEN_FORCE_NEW, true);
    List<ForecastModelRunInventory.VertCoord> vcList = fmrInv.getVertCoords();
    for (ForecastModelRunInventory.VertCoord vc : vcList) {
      CoordinateAxis1D axis = vc.axis;
      if (axis == null)
        System.out.println(" No Axis " + vc.getName());
      else {
        if (axis.isInterval()) {
          System.out.println(" Layer " + vc.getName() + " contig= " + axis.isContiguous());
          // see if theres any TimeCoord that use this
          findGridsForVertCoord(fmrDef, vc);
        }
      }
      boolean got = fmrDef.findVertCoordByName(vc.getName()) != null;
      if (!got)
        System.out.println(" ***NOT " + vc.getName());
    }
  }

  static void findGridsForVertCoord(FmrcDefinition fmrDef, ForecastModelRunInventory.VertCoord vc) {
    for (RunSeq runSeq : fmrDef.runSequences) {
      for (Grid grid : runSeq.vars) {
        if ((grid.vtc != null) && (grid.vtc.vc == vc)) {
          List restrictList = grid.vtc.restrictList;
          if (restrictList != null && restrictList.size() > 0)
            System.out.println(" TimeVertCoord refers to this vertical coordinate");
        }
      }
    }
  }

  public static String[] fmrcDatasets = {
          "NCEP/GFS/Alaska_191km",
          "NCEP/GFS/CONUS_80km",
          "NCEP/GFS/CONUS_95km",
          "NCEP/GFS/CONUS_191km",
          "NCEP/GFS/Global_0p5deg",
          "NCEP/GFS/Global_onedeg",
          "NCEP/GFS/Global_2p5deg",
          "NCEP/GFS/Hawaii_160km",
          "NCEP/GFS/N_Hemisphere_381km",
          "NCEP/GFS/Puerto_Rico_191km",

          "NCEP/NAM/Alaska_11km",
          "NCEP/NAM/Alaska_22km",
          "NCEP/NAM/Alaska_45km/noaaport",
          "NCEP/NAM/Alaska_45km/conduit",
          "NCEP/NAM/Alaska_95km",
          "NCEP/NAM/CONUS_12km/conduit",
          "NCEP/NAM/CONUS_20km/surface",
          "NCEP/NAM/CONUS_20km/selectsurface",
          "NCEP/NAM/CONUS_20km/noaaport",
          "NCEP/NAM/CONUS_40km/conduit",
          "NCEP/NAM/CONUS_80km",
          "NCEP/NAM/Polar_90km",

          "NCEP/RUC2/CONUS_20km/surface",
          "NCEP/RUC2/CONUS_20km/pressure",
          "NCEP/RUC2/CONUS_20km/hybrid",
          "NCEP/RUC2/CONUS_40km",
          "NCEP/RUC/CONUS_80km",

          "NCEP/DGEX/CONUS_12km",
          "NCEP/DGEX/Alaska_12km",

          /*
          "NCEP/GEFS/Global_1p0deg_Ensemble/derived",
          "NCEP/GEFS/Global_1p0deg_Ensemble/member",
          */

          "NCEP/SREF/CONUS_40km/ensprod",
          "NCEP/SREF/CONUS_40km/ensprod_biasc",
          /* "NCEP/SREF/CONUS_40km/pgrb_biasc", */
          "NCEP/SREF/Alaska_45km/ensprod",
          "NCEP/SREF/PacificNE_0p4/ensprod",

          "NCEP/NDFD/CONUS_5km",

          "NCEP/WW3/Alaskan_4minute",
          "NCEP/WW3/Alaskan_10minute",
          "NCEP/WW3/Atlantic_4minute",
          "NCEP/WW3/Atlantic_10minute",
          "NCEP/WW3/EasternPacific_10minute",
          "NCEP/WW3/Global_30minute",
          "NCEP/WW3/WestCoast_4minute",
          "NCEP/WW3/WestCoast_10minute",
  };

  public static String[] fmrcDatasets_41 = {
          "NCEP/GFS/Alaska_191km",
          "NCEP/GFS/CONUS_80km",
          "NCEP/GFS/CONUS_95km",
          "NCEP/GFS/CONUS_191km",
          "NCEP/GFS/Global_0p5deg",
          "NCEP/GFS/Global_onedeg",
          "NCEP/GFS/Global_2p5deg",
          "NCEP/GFS/Hawaii_160km",
          "NCEP/GFS/N_Hemisphere_381km",
          "NCEP/GFS/Puerto_Rico_191km",

          "NCEP/NAM/Alaska_11km",
          "NCEP/NAM/Alaska_22km",
          "NCEP/NAM/Alaska_45km/noaaport",
          "NCEP/NAM/Alaska_45km/conduit",
          "NCEP/NAM/Alaska_95km",
          "NCEP/NAM/CONUS_12km/conduit",
          "NCEP/NAM/CONUS_20km/surface",
          "NCEP/NAM/CONUS_20km/selectsurface",
          "NCEP/NAM/CONUS_20km/noaaport",
          "NCEP/NAM/CONUS_40km/conduit",
          "NCEP/NAM/CONUS_80km",
          "NCEP/NAM/Polar_90km",

          "NCEP/RUC2/CONUS_20km/surface",
          "NCEP/RUC2/CONUS_20km/pressure",
          "NCEP/RUC2/CONUS_20km/hybrid",
          "NCEP/RUC2/CONUS_40km",
          "NCEP/RUC/CONUS_80km",

          "NCEP/DGEX/CONUS_12km",
          "NCEP/DGEX/Alaska_12km",

          /*
          "NCEP/GEFS/Global_1p0deg_Ensemble/derived",
          "NCEP/GEFS/Global_1p0deg_Ensemble/member",


          "NCEP/SREF/CONUS_40km/ensprod",
          "NCEP/SREF/CONUS_40km/ensprod_biasc",
          // "NCEP/SREF/CONUS_40km/pgrb_biasc",
          "NCEP/SREF/Alaska_45km/ensprod",
          "NCEP/SREF/PacificNE_0p4/ensprod",
                   */

          "NCEP/NDFD/CONUS_5km",
  };



  private static String fmrcDefinitionDir = "C:/dev/tds/thredds/tds/src/main/webapp/WEB-INF/altContent/idd/thredds/modelInventory/";
  private static String[] fmrcDefinitionFiles;

  public static String[] getDefinitionFiles() {
    if (fmrcDefinitionFiles == null) {
      fmrcDefinitionFiles = new String[fmrcDatasets.length];
      int count = 0;
      for (String ds : fmrcDatasets) {
        fmrcDefinitionFiles[count++] = fmrcDefinitionDir + StringUtil.replace(ds, '/', "-") + ".fmrcDefinition.xml";
      }
    }
    return fmrcDefinitionFiles;
  }


  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

  private static String[] exampleFiles = {
          /* "R:/testdata2/motherlode/grid/GFS_Alaska_191km_20060802_1200.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-Alaska_191km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_CONUS_80km_20060802_0600.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-CONUS_80km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_CONUS_191km_20060802_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-CONUS_191km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_CONUS_95km_20060802_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-CONUS_95km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_Global_2p5deg_20060801_1200.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-Global_2p5deg.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_Global_onedeg_20060802_0600.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-Global_onedeg.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_Hawaii_160km_20060730_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-Hawaii_160km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_N_Hemisphere_381km_20060801_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-N_Hemisphere_381km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_Puerto_Rico_191km_20060731_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-Puerto_Rico_191km.fmrcDefinition.xml",

      "R:/testdata2/motherlode/grid/NAM_Alaska_22km_20060731_1200.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-Alaska_22km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_Alaska_45km_conduit_20060801_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-Alaska_45km-conduit.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_Alaska_45km_noaaport_20060730_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-Alaska_45km-noaaport.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_Alaska_95km_20060801_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-Alaska_95km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_CONUS_20km_noaaport_20060731_0600.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-CONUS_20km-noaaport.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_CONUS_20km_selectsurface_20060801_0600.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-CONUS_20km-selectsurface.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_CONUS_20km_surface_20060801_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-CONUS_20km-surface.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_CONUS_40km_conduit_20060801_0600.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-CONUS_40km-conduit.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_CONUS_40km_noaaport_20060731_1800.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-CONUS_40km-noaaport.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_CONUS_80km_20060728_1200.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-CONUS_80km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_Polar_90km_20060730_0000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-Polar_90km.fmrcDefinition.xml",

      "R:/testdata2/motherlode/grid/RUC2_CONUS_20km_hybrid_20060802_2100.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-RUC2-CONUS_20km-hybrid.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/RUC2_CONUS_20km_pressure_20060802_2000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-RUC2-CONUS_20km-pressure.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/RUC2_CONUS_20km_surface_20060802_1700.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-RUC2-CONUS_20km-surface.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/RUC_CONUS_40km_20060802_2000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-RUC-CONUS_40km.fmrcDefinition.xml", //
      "R:/testdata2/motherlode/grid/RUC_CONUS_80km_20060802_2000.grib1", "R:/testdata2/motherlode/grid/modelDefs/NCEP-RUC-CONUS_80km.fmrcDefinition.xml",

      "R:/testdata2/motherlode/grid/DGEX_Alaska_12km_20060731_0000.grib2", "R:/testdata2/motherlode/grid/modelDefs/NCEP-DGEX-Alaska_12km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/DGEX_CONUS_12km_20060730_1800.grib2", "R:/testdata2/motherlode/grid/modelDefs/NCEP-DGEX-CONUS_12km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/GFS_Global_0p5deg_20060726_0600.grib2", "R:/testdata2/motherlode/grid/modelDefs/NCEP-GFS-Global_0p5deg.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_Alaska_11km_20060802_1200.grib2", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-Alaska_11km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NAM_CONUS_12km_20060801_1200.grib2", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NAM-CONUS_12km.fmrcDefinition.xml",
      "R:/testdata2/motherlode/grid/NDFD_CONUS_5km_20060731_1200.grib2", "R:/testdata2/motherlode/grid/modelDefs/NCEP-NDFD-CONUS_5km.fmrcDefinition.xml",  // */

          "R:/testdata/motherlode/grid/RUC2_CONUS_20km_surface_20060825_1400.grib2", "R:/testdata/motherlode/grid/modelDefs/NCEP-RUC2-CONUS_20km-surface.fmrcDefinition.xml",

  };

  public static void main(String args[]) throws IOException {
    for (int i = 0; i < exampleFiles.length; i += 2)
      convertIds(exampleFiles[i], exampleFiles[i + 1]);

    //for (int i = 0; i < defs.length; i+=2)
    //  showVertCoords(defs[i], defs[i+1]);


  }

}
TOP

Related Classes of ucar.nc2.dt.fmrc.FmrcDefinition$VertTimeCoord

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.