ui/src/main/java/ucar/nc2/ui/grib/Grib2ReportPanel.java
private void doRename(Formatter f, MCollection dcm, boolean useIndex) throws IOException {
    f.format("CHECK Grib-2 Names: Old vs New for collection %s%n", dcm.getCollectionName());

    List<VarName> varNames = new ArrayList<>(3000);
    Map<String, List<String>> gridsAll = new HashMap<>(1000); // old -> list<new>
    int countExactMatch = 0;
    int countExactMatchIg = 0;
    int countOldVars = 0;

    for (MFile mfile : dcm.getFilesSorted()) {
      f.format("%n%s%n", mfile.getPath());
      Map<Integer, GridMatch> gridsNew = getGridsNew(mfile, f);
      Map<Integer, GridMatch> gridsOld = getGridsOld(mfile, f);

      // look for exact match on name
      Set<String> namesNew = new HashSet<>(gridsNew.size());
      for (GridMatch gm : gridsNew.values())
        namesNew.add(gm.grid.getFullName());
      for (GridMatch gm : gridsOld.values()) {
        if (namesNew.contains(gm.grid.getFullName())) countExactMatch++;
        countOldVars++;
      }

      // look for exact match on hashcode
      for (GridMatch gm : gridsNew.values()) {
        GridMatch match = gridsOld.get(gm.hashCode());
        if (match != null) {
          gm.match = match;
          match.match = gm;
        }
      }

      // look for alternative match
      for (GridMatch gm : gridsNew.values()) {
        if (gm.match == null) {
          GridMatch match = altMatch(gm, gridsOld.values());
          if (match != null) {
            gm.match = match;
            match.match = gm;
          }
        }
      }

      // print out match
      f.format("%n");
      List<GridMatch> listNew = new ArrayList<>(gridsNew.values());
      Collections.sort(listNew);
      for (GridMatch gm : listNew) {
        f.format(" %s%n", gm.grid.findAttributeIgnoreCase(Grib.VARIABLE_ID_ATTNAME));
        f.format(" %s (%d)%n", gm.grid.getFullName(), gm.hashCode());
        if (gm.match != null) {
          boolean exact = gm.match.grid.getFullName().equals(gm.grid.getFullName());
          boolean exactIg = !exact && gm.match.grid.getFullName().equalsIgnoreCase(gm.grid.getFullName());
          if (exactIg) countExactMatchIg++;
          String status = exact ? " " : exactIg ? "**" : " *";
          f.format("%s%s (%d)%n", status, gm.match.grid.getFullName(), gm.match.hashCode());
        }
        f.format("%n");
      }

      // print out missing
      f.format("%nMISSING MATCHES IN NEW%n");
      List<GridMatch> list = new ArrayList<>(gridsNew.values());
      Collections.sort(list);
      for (GridMatch gm : list) {
        if (gm.match == null)
          f.format(" %s (%s) == %s%n", gm.grid.getFullName(), gm.show(), gm.grid.getDescription());
      }
      f.format("%nMISSING MATCHES IN OLD%n");
      List<GridMatch> listOld = new ArrayList<>(gridsOld.values());
      Collections.sort(listOld);
      for (GridMatch gm : listOld) {
        if (gm.match == null)
          f.format(" %s (%s)%n", gm.grid.getFullName(), gm.show());
      }

      // add to gridsAll to track old -> new mapping
      for (GridMatch gmOld : listOld) {
        String key = gmOld.grid.getShortName();
        List<String> newGrids = gridsAll.get(key);
        if (newGrids == null) {
          newGrids = new ArrayList<>();
          gridsAll.put(key, newGrids);
        }
        if (gmOld.match != null) {
          String keyNew = gmOld.match.grid.getShortName();
          if (!newGrids.contains(keyNew)) newGrids.add(keyNew);
        }
      }

      // add matches to VarNames
      for (GridMatch gmOld : listOld) {
        if (gmOld.match == null) {
          f.format("MISSING %s (%s)%n", gmOld.grid.getFullName(), gmOld.show());
          continue;
        }
        Attribute att = gmOld.match.grid.findAttributeIgnoreCase(Grib.VARIABLE_ID_ATTNAME);
        String varId = att == null ? "" : att.getStringValue();
        varNames.add(new VarName(mfile.getName(), gmOld.grid.getShortName(), gmOld.match.grid.getShortName(), varId));
      }

    }

    // show old -> new mapping
    f.format("%nOLD -> NEW MAPPINGS%n");
    List<String> keys = new ArrayList<>(gridsAll.keySet());
    int total = keys.size();
    int dups = 0;
    Collections.sort(keys);
    for (String key : keys) {
      f.format(" OLD %s%n", key);
      List<String> newGrids = gridsAll.get(key);
      Collections.sort(newGrids);
      if (newGrids.size() > 1) dups++;
      for (String newKey : newGrids)
        f.format(" NEW %s%n", newKey);
      f.format("%n");
    }

    f.format("Exact matches=%d  Exact ignore case=%d  totalOldVars=%d%n", countExactMatch, countExactMatchIg, countOldVars);
    f.format("Number with more than one map=%d total=%d%n", dups, total);

    // old -> new mapping xml table
    if (!useIndex) {
      Element rootElem = new Element("gribVarMap");
      Document doc = new Document(rootElem);
      rootElem.setAttribute("collection", dcm.getCollectionName());

      String currentDs = null;
      Element dsElem = null;
      for (VarName vn : varNames) {
        if (!vn.dataset.equals(currentDs)) {
          dsElem = new Element("dataset");
          rootElem.addContent(dsElem);
          dsElem.setAttribute("name", vn.dataset);
          currentDs = vn.dataset;
        }
        Element param = new Element("param");
        dsElem.addContent(param);
        param.setAttribute("oldName", vn.oldVar);
        param.setAttribute("newName", vn.newVar);
        param.setAttribute("varId", vn.varId);
      }

      FileOutputStream fout = new FileOutputStream("C:/tmp/grib2VarMap.xml");
      XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
      fmt.output(doc, fout);
      fout.close();
    }

    /*  old -> new mapping xml table
   if (!useIndex) {
     Element rootElem = new Element("gribVarMap");
     Document doc = new Document(rootElem);
     rootElem.setAttribute("collection", dcm.getCollectionName());

     for (String key : keys) {
       Element param = new Element("param");
       rootElem.addContent(param);
       param.setAttribute("oldName", key);
       List<String> newGrids = gridsAll.get(key);
       Collections.sort(newGrids);
       for (String newKey : newGrids)
         param.addContent(new Element("newName").addContent(newKey));
     }

     FileOutputStream fout = new FileOutputStream("C:/tmp/gribVarMap.xml");
     XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
     fmt.output(doc, fout);
     fout.close();
   } */
  }

  private GridMatch altMatch(GridMatch want, Collection<GridMatch> test) {
    // look for scale factor errors in prob
    for (GridMatch gm : test) {
      if (gm.match != null) continue; // already matched
      if (gm.altMatch(want)) {
        //gm.altMatch(want); //debug
        return gm;
      }
    }

    // give up matching the prob
    for (GridMatch gm : test) {
      if (gm.match != null) continue; // already matched
      if (gm.altMatchNoProb(want)) {
        //gm.altMatchNoProb(want); // debug
        return gm;
      }
    }

    return null;
  }
private void doRename(Formatter f, MCollection dcm, boolean useIndex) throws IOException {
    f.format("CHECK Grib-2 Names: Old vs New for collection %s%n", dcm.getCollectionName());

    List<VarName> varNames = new ArrayList<>(3000);
    Map<String, List<String>> gridsAll = new HashMap<>(1000); // old -> list<new>
    int countExactMatch = 0;
    int countExactMatchIg = 0;
    int countOldVars = 0;

    for (MFile mfile : dcm.getFilesSorted()) {
      f.format("%n%s%n", mfile.getPath());
      Map<Integer, GridMatch> gridsNew = getGridsNew(mfile, f);
      Map<Integer, GridMatch> gridsOld = getGridsOld(mfile, f);

      // look for exact match on name
      Set<String> namesNew = new HashSet<>(gridsNew.size());
      for (GridMatch gm : gridsNew.values())
        namesNew.add(gm.grid.getFullName());
      for (GridMatch gm : gridsOld.values()) {
        if (namesNew.contains(gm.grid.getFullName())) countExactMatch++;
        countOldVars++;
      }

      // look for exact match on hashcode
      for (GridMatch gm : gridsNew.values()) {
        GridMatch match = gridsOld.get(gm.hashCode());
        if (match != null) {
          gm.match = match;
          match.match = gm;
        }
      }

      // look for alternative match
      for (GridMatch gm : gridsNew.values()) {
        if (gm.match == null) {
          GridMatch match = altMatch(gm, gridsOld.values());
          if (match != null) {
            gm.match = match;
            match.match = gm;
          }
        }
      }

      // print out match
      f.format("%n");
      List<GridMatch> listNew = new ArrayList<>(gridsNew.values());
      Collections.sort(listNew);
      for (GridMatch gm : listNew) {
        f.format(" %s%n", gm.grid.findAttributeIgnoreCase(Grib.VARIABLE_ID_ATTNAME));
        f.format(" %s (%d)%n", gm.grid.getFullName(), gm.hashCode());
        if (gm.match != null) {
          boolean exact = gm.match.grid.getFullName().equals(gm.grid.getFullName());
          boolean exactIg = !exact && gm.match.grid.getFullName().equalsIgnoreCase(gm.grid.getFullName());
          if (exactIg) countExactMatchIg++;
          String status = exact ? " " : exactIg ? "**" : " *";
          f.format("%s%s (%d)%n", status, gm.match.grid.getFullName(), gm.match.hashCode());
        }
        f.format("%n");
      }

      // print out missing
      f.format("%nMISSING MATCHES IN NEW%n");
      List<GridMatch> list = new ArrayList<>(gridsNew.values());
      Collections.sort(list);
      for (GridMatch gm : list) {
        if (gm.match == null)
          f.format(" %s (%s) == %s%n", gm.grid.getFullName(), gm.show(), gm.grid.getDescription());
      }
      f.format("%nMISSING MATCHES IN OLD%n");
      List<GridMatch> listOld = new ArrayList<>(gridsOld.values());
      Collections.sort(listOld);
      for (GridMatch gm : listOld) {
        if (gm.match == null)
          f.format(" %s (%s)%n", gm.grid.getFullName(), gm.show());
      }

      // add to gridsAll to track old -> new mapping
      for (GridMatch gmOld : listOld) {
        String key = gmOld.grid.getShortName();
        List<String> newGrids = gridsAll.get(key);
        if (newGrids == null) {
          newGrids = new ArrayList<>();
          gridsAll.put(key, newGrids);
        }
        if (gmOld.match != null) {
          String keyNew = gmOld.match.grid.getShortName();
          if (!newGrids.contains(keyNew)) newGrids.add(keyNew);
        }
      }

      // add matches to VarNames
      for (GridMatch gmOld : listOld) {
        if (gmOld.match == null) {
          f.format("MISSING %s (%s)%n", gmOld.grid.getFullName(), gmOld.show());
          continue;
        }
        Attribute att = gmOld.match.grid.findAttributeIgnoreCase(Grib.VARIABLE_ID_ATTNAME);
        String varId = att == null ? "" : att.getStringValue();
        varNames.add(new VarName(mfile.getName(), gmOld.grid.getShortName(), gmOld.match.grid.getShortName(), varId));
      }

    }

    // show old -> new mapping
    f.format("%nOLD -> NEW MAPPINGS%n");
    List<String> keys = new ArrayList<>(gridsAll.keySet());
    int total = keys.size();
    int dups = 0;
    Collections.sort(keys);
    for (String key : keys) {
      f.format(" OLD %s%n", key);
      List<String> newGrids = gridsAll.get(key);
      Collections.sort(newGrids);
      if (newGrids.size() > 1) dups++;
      for (String newKey : newGrids)
        f.format(" NEW %s%n", newKey);
      f.format("%n");
    }

    f.format("Exact matches=%d  Exact ignore case=%d  totalOldVars=%d%n", countExactMatch, countExactMatchIg, countOldVars);
    f.format("Number with more than one map=%d total=%d%n", dups, total);

    // old -> new mapping xml table
    if (!useIndex) {
      Element rootElem = new Element("gribVarMap");
      Document doc = new Document(rootElem);
      rootElem.setAttribute("collection", dcm.getCollectionName());

      String currentDs = null;
      Element dsElem = null;
      for (VarName vn : varNames) {
        if (!vn.dataset.equals(currentDs)) {
          dsElem = new Element("dataset");
          rootElem.addContent(dsElem);
          dsElem.setAttribute("name", vn.dataset);
          currentDs = vn.dataset;
        }
        Element param = new Element("param");
        dsElem.addContent(param);
        param.setAttribute("oldName", vn.oldVar);
        param.setAttribute("newName", vn.newVar);
        param.setAttribute("varId", vn.varId);
      }

      FileOutputStream fout = new FileOutputStream("C:/tmp/grib2VarMap.xml");
      XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
      fmt.output(doc, fout);
      fout.close();
    }

    /*  old -> new mapping xml table
   if (!useIndex) {
     Element rootElem = new Element("gribVarMap");
     Document doc = new Document(rootElem);
     rootElem.setAttribute("collection", dcm.getCollectionName());

     for (String key : keys) {
       Element param = new Element("param");
       rootElem.addContent(param);
       param.setAttribute("oldName", key);
       List<String> newGrids = gridsAll.get(key);
       Collections.sort(newGrids);
       for (String newKey : newGrids)
         param.addContent(new Element("newName").addContent(newKey));
     }

     FileOutputStream fout = new FileOutputStream("C:/tmp/gribVarMap.xml");
     XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
     fmt.output(doc, fout);
     fout.close();
   } */
  }

  private GridMatch altMatch(GridMatch want, Collection<GridMatch> test) {
    // look for scale factor errors in prob
    for (GridMatch gm : test) {
      if (gm.match != null) continue; // already matched
      if (gm.altMatch(want)) {
        //gm.altMatch(want); //debug
        return gm;
      }
    }

    // give up matching the prob
    for (GridMatch gm : test) {
      if (gm.match != null) continue; // already matched
      if (gm.altMatchNoProb(want)) {
        //gm.altMatchNoProb(want); // debug
        return gm;
      }
    }

    return null;
  }
/////////////////////////////////////////////////////////////////////////////////