All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.nc2.dt.grid.GridDatasetInfo Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */

package ucar.nc2.dt.grid;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ucar.ma2.DataType;
import ucar.nc2.Attribute;
import ucar.nc2.Dimension;
import ucar.nc2.constants.AxisType;
import ucar.nc2.dataset.CoordinateAxis;
import ucar.nc2.dataset.CoordinateAxis1D;
import ucar.nc2.dataset.CoordinateTransform;
import ucar.nc2.dt.GridCoordSystem;
import ucar.nc2.dt.GridDataset;
import ucar.nc2.dt.GridDatatype;
import ucar.nc2.dt.grid.gis.GridBoundariesExtractor;
import ucar.nc2.time.CalendarDate;
import ucar.nc2.write.NcmlWriter;
import ucar.unidata.geoloc.LatLonRect;
import ucar.unidata.geoloc.ProjectionRect;
import ucar.unidata.util.Parameter;

/**
 * A helper class to GridDataset; creates a GridDataset XML document.
 * This is a candidate for the XML representation of the Grid SDT.
 * Used to create form for NetcdfSubsetService for Grids.
 *
 * @author caron
 */
public class GridDatasetInfo {
  private static final Logger logger = LoggerFactory.getLogger(GridDatasetInfo.class);

  private ucar.nc2.dt.GridDataset gds;
  private String path;

  public GridDatasetInfo(ucar.nc2.dt.GridDataset gds, String path) {
    this.gds = gds;
    this.path = path;
  }

  /**
   * Write the information as an XML document
   *
   * @param doc write XML for this Document
   * @return String output
   */
  public String writeXML(Document doc) {
    XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
    return fmt.outputString(doc);
  }

  /**
   * Write the information as an XML document
   *
   * @param doc write XML for this Document
   * @param os write to this output stream
   * @throws java.io.IOException on write error
   */
  public void writeXML(Document doc, OutputStream os) throws IOException {
    XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
    fmt.output(doc, os);
  }

  /**
   * Create the "Dataset Description" XML document from this GridDataset
   *
   * @return a JDOM Document
   */
  public Document makeDatasetDescription() {
    Element rootElem = new Element("gridDataset");
    Document doc = new Document(rootElem);
    rootElem.setAttribute("location", gds.getLocation());
    if (null != path)
      rootElem.setAttribute("path", path);

    /*
     * dimensions
     * List dims = getDimensions(gds);
     * for (int j = 0; j < dims.size(); j++) {
     * Dimension dim = (Dimension) dims.get(j);
     * rootElem.addContent(ucar.nc2.ncml.NcMLWriter.writeDimension(dim, null));
     * }
     */

    // coordinate axes
    for (CoordinateAxis axis : getCoordAxes(gds)) {
      rootElem.addContent(writeAxis(axis));
    }

    /*
     * grids
     * List grids = gds.getGrids();
     * Collections.sort(grids, new GridComparator());
     * for (int i = 0; i < grids.size(); i++) {
     * GeoGrid grid = (GeoGrid) grids.get(i);
     * rootElem.addContent(writeGrid(grid));
     * }
     */

    /*
     * coordinate systems
     * List gridSets = gds.getGridsets();
     * for (int i = 0; i < gridSets.size(); i++) {
     * GridDataset.Gridset gridset = (GridDataset.Gridset) gridSets.get(i);
     * rootElem.addContent(writeCoordSys(gridset.getGeoCoordSystem()));
     * }
     */

    // gridSets
    List gridSets = gds.getGridsets();
    gridSets.sort(new GridSetComparator());
    for (GridDataset.Gridset gridset : gridSets) {
      rootElem.addContent(writeGridSet(gridset));
    }

    // coordinate transforms
    for (CoordinateTransform ct : getCoordTransforms(gds)) {
      rootElem.addContent(writeCoordTransform(ct));
    }

    /*
     * global attributes
     * Iterator atts = gds.getGlobalAttributes().iterator();
     * while (atts.hasNext()) {
     * ucar.nc2.Attribute att = (ucar.nc2.Attribute) atts.next();
     * rootElem.addContent(ucar.nc2.ncml.NcMLWriter.writeAttribute(att, "attribute", null));
     * }
     */

    // add lat/lon bounding box
    LatLonRect bb = gds.getBoundingBox();
    if (bb != null)
      rootElem.addContent(writeBoundingBox(bb));

    // add date range
    CalendarDate start = gds.getCalendarDateStart();
    CalendarDate end = gds.getCalendarDateEnd();
    if ((start != null) && (end != null)) {
      Element dateRange = new Element("TimeSpan");
      dateRange.addContent(new Element("begin").addContent(start.toString()));
      dateRange.addContent(new Element("end").addContent(end.toString()));
      rootElem.addContent(dateRange);
    }

    // add accept list
    addAcceptList(rootElem);

    // elem.addContent(new Element("accept").addContent("xml"));
    // elem.addContent(new Element("accept").addContent("csv"));
    // elem.addContent(new Element("accept").addContent("netcdf"));
    return doc;
  }

  /**
   * Returns a WKT polygon with the dataset boundaries
   * 
   * @return WKT string
   */
  public String getDatasetBoundariesWKT() {

    return GridBoundariesExtractor.valueOf(gds).getDatasetBoundariesWKT();
  }


  /**
   * Create the "Grid Form" XML document from this GridDataset.
   * Used to create the Grid HTML form, cause I dont know XSLT
   *
   * @return the JDOM Document
   */
  public Document makeGridForm() {
    Element rootElem = new Element("gridForm");
    Document doc = new Document(rootElem);
    rootElem.setAttribute("location", gds.getLocation());
    if (null != path)
      rootElem.setAttribute("path", path);

    // its all about grids
    List grids = gds.getGrids();
    grids.sort(new GridComparator()); // sort by time axis, vert axis, grid name


    CoordinateAxis currentTime = null;
    CoordinateAxis currentVert = null;
    Element timeElem = null;
    Element vertElem = null;
    boolean newTime;

    for (int i = 0; i < grids.size(); i++) {
      GeoGrid grid = (GeoGrid) grids.get(i);
      GridCoordSystem gcs = grid.getCoordinateSystem();


      CoordinateAxis time = gcs.getTimeAxis();
      CoordinateAxis vert = gcs.getVerticalAxis();

      // Assuming all variables in dataset has ensemble dim if one has
      if (i == 0) {
        CoordinateAxis1D ens = gcs.getEnsembleAxis();
        if (ens != null) {
          Element ensAxisEl = writeAxis2(ens, "ensemble");
          rootElem.addContent(ensAxisEl);
        }
      }

      if ((i == 0) || !compareAxis(time, currentTime)) {
        timeElem = new Element("timeSet");
        rootElem.addContent(timeElem);
        Element timeAxisElement = writeAxis2(time, "time");
        if (timeAxisElement != null)
          timeElem.addContent(timeAxisElement);
        currentTime = time;
        newTime = true;
      } else {
        newTime = false;
      }

      if (newTime || !compareAxis(vert, currentVert)) {
        vertElem = new Element("vertSet");
        timeElem.addContent(vertElem);
        Element vertAxisElement = writeAxis2(vert, "vert");
        if (vertAxisElement != null)
          vertElem.addContent(vertAxisElement);
        currentVert = vert;
      }

      vertElem.addContent(writeGrid(grid));
    }

    // add lat/lon bounding box
    LatLonRect bb = gds.getBoundingBox();
    if (bb != null)
      rootElem.addContent(writeBoundingBox(bb));

    // add projected bounding box
    // --> Asuming all gridSets have the same coordinates and bbox
    ProjectionRect rect = grids.get(0).getCoordinateSystem().getBoundingBox();

    Element projBBOX = new Element("projectionBox");
    Element minx = new Element("minx");
    minx.addContent(Double.valueOf(rect.getMinX()).toString());
    projBBOX.addContent(minx);
    Element maxx = new Element("maxx");
    maxx.addContent(Double.valueOf(rect.getMaxX()).toString());
    projBBOX.addContent(maxx);
    Element miny = new Element("miny");
    miny.addContent(Double.valueOf(rect.getMinY()).toString());
    projBBOX.addContent(miny);
    Element maxy = new Element("maxy");
    maxy.addContent(Double.valueOf(rect.getMaxY()).toString());
    projBBOX.addContent(maxy);

    rootElem.addContent(projBBOX);

    // add date range
    CalendarDate start = gds.getCalendarDateStart();
    CalendarDate end = gds.getCalendarDateEnd();
    if ((start != null) && (end != null)) {
      Element dateRange = new Element("TimeSpan");
      dateRange.addContent(new Element("begin").addContent(start.toString()));
      dateRange.addContent(new Element("end").addContent(end.toString()));
      rootElem.addContent(dateRange);
    }

    // add accept list
    addAcceptList(rootElem);

    // Element elem = new Element("AcceptList");
    // elem.addContent(new Element("accept").addContent("xml"));
    // elem.addContent(new Element("accept").addContent("csv"));
    // elem.addContent(new Element("accept").addContent("netcdf"));
    // rootElem.addContent(elem);
    return doc;
  }

  private void addAcceptList(Element rootElement) {

    // add accept list
    Element elem = new Element("AcceptList");
    // accept list for Grid As Point requests
    Element gridAsPoint = new Element("GridAsPoint");

    // LOOK this is wrong - should be using SupportedOperation class or something
    gridAsPoint.addContent(new Element("accept").addContent("xml").setAttribute("displayName", "xml"));
    gridAsPoint.addContent(new Element("accept").addContent("xml_file").setAttribute("displayName", "xml (file)"));
    gridAsPoint.addContent(new Element("accept").addContent("csv").setAttribute("displayName", "csv"));
    gridAsPoint.addContent(new Element("accept").addContent("csv_file").setAttribute("displayName", "csv (file)"));
    gridAsPoint.addContent(new Element("accept").addContent("geocsv").setAttribute("displayName", "geocsv"));
    gridAsPoint
        .addContent(new Element("accept").addContent("geocsv_file").setAttribute("displayName", "geocsv (file)"));
    gridAsPoint.addContent(new Element("accept").addContent("netcdf").setAttribute("displayName", "netcdf"));

    // accept list for Grid requests
    Element grids = new Element("Grid");
    grids.addContent(new Element("accept").addContent("netcdf").setAttribute("displayName", "netcdf"));
    // Check if netcdf4 is available
    // try{
    // if( Nc4Iosp.isClibraryPresent() ){
    // grids.addContent(new Element("accept").addContent("netcdf4"));
    // gridAsPoint.addContent(new Element("accept").addContent("netcdf4"));
    // }
    // }catch(UnsatisfiedLinkError e){
    // //Log this in threddsServlet.log ??
    // }

    elem.addContent(gridAsPoint);
    elem.addContent(grids);
    rootElement.addContent(elem);
  }

  private Element writeAxis2(CoordinateAxis axis, String name) {
    if (axis == null)
      return null;

    NcmlWriter ncmlWriter = new NcmlWriter();

    Element varElem = new Element(name);
    varElem.setAttribute("name", axis.getFullName());
    varElem.setAttribute("shape", getShapeString(axis.getShape())); // axis.getDimensionsString());

    DataType dt = axis.getDataType();
    varElem.setAttribute("type", dt.toString());

    AxisType axisType = axis.getAxisType();
    if (null != axisType)
      varElem.setAttribute("axisType", axisType.toString());

    // attributes
    for (Attribute att : axis.attributes())
      varElem.addContent(ncmlWriter.makeAttributeElement(att));

    try {
      Element values = ncmlWriter.makeValuesElement(axis, false);
      values.setAttribute("npts", Long.toString(axis.getSize()));
      varElem.addContent(values);
    } catch (IOException e) {
      String message = String.format("Couldn't read values for %s. Omitting  element.", axis.getFullName());
      logger.warn(message, e);
    }

    return varElem;
  }

  private boolean compareAxis(CoordinateAxis axis1, CoordinateAxis axis2) {
    if (axis1 == axis2)
      return true;

    if (axis1 == null)
      return false;
    if (axis2 == null)
      return false;

    return axis1.equals(axis2);
  }

  // sort by time, then vert, then name
  private static class GridComparator implements Comparator {

    // Returns a -1, 0, 1 if the first argument is less than, equal to, or greater than the second.
    public int compare(GridDatatype grid1, GridDatatype grid2) {
      GridCoordSystem gcs1 = grid1.getCoordinateSystem();
      GridCoordSystem gcs2 = grid2.getCoordinateSystem();

      CoordinateAxis time1 = gcs1.getTimeAxis();
      CoordinateAxis time2 = gcs2.getTimeAxis();
      int ret = compareAxis(time1, time2);
      if (ret != 0)
        return ret;

      CoordinateAxis vert1 = gcs1.getVerticalAxis();
      CoordinateAxis vert2 = gcs2.getVerticalAxis();
      ret = compareAxis(vert1, vert2);
      if (ret != 0)
        return ret;

      return grid1.getFullName().compareTo(grid2.getFullName());
    }

    private int compareAxis(CoordinateAxis axis1, CoordinateAxis axis2) {
      if (axis1 == axis2)
        return 0;

      if (axis1 == null)
        return -1;
      if (axis2 == null)
        return 1;

      return axis1.getFullName().compareTo(axis2.getFullName());
    }

  }

  private List getCoordAxes(ucar.nc2.dt.GridDataset gds) {
    Set axesHash = new HashSet<>();

    for (ucar.nc2.dt.GridDataset.Gridset gridset : gds.getGridsets()) {
      GridCoordSystem gcs = gridset.getGeoCoordSystem();
      axesHash.addAll(gcs.getCoordinateAxes());
    }

    return axesHash.stream().sorted().collect(Collectors.toList());
  }

  private List getCoordTransforms(ucar.nc2.dt.GridDataset gds) {
    Set ctHash = new HashSet<>();

    for (ucar.nc2.dt.GridDataset.Gridset gridset : gds.getGridsets()) {
      GridCoordSystem gcs = gridset.getGeoCoordSystem();
      ctHash.addAll(gcs.getCoordinateTransforms());
    }

    return ctHash.stream().sorted().collect(Collectors.toList());
  }

  /*
   * private List getDimensions(ucar.nc2.dt.GridDataset gds) {
   * HashSet dimHash = new HashSet();
   * List grids = gds.getGrids();
   * for (int i = 0; i < grids.size(); i++) {
   * GeoGrid grid = (GeoGrid) grids.get(i);
   * List dims = grid.getDimensions();
   * for (int j = 0; j < dims.size(); j++) {
   * Dimension dim = (Dimension) dims.get(j);
   * dimHash.add(dim);
   * }
   * }
   * List list = Arrays.asList(dimHash.toArray());
   * Collections.sort(list);
   * return list;
   * }
   */

  private Element writeAxis(CoordinateAxis axis) {
    NcmlWriter ncmlWriter = new NcmlWriter();

    Element varElem = new Element("axis");
    varElem.setAttribute("name", axis.getFullName());
    varElem.setAttribute("shape", getShapeString(axis.getShape())); // axis.getDimensionsString());

    DataType dt = axis.getDataType();
    varElem.setAttribute("type", dt.toString());

    AxisType axisType = axis.getAxisType();
    if (null != axisType)
      varElem.setAttribute("axisType", axisType.toString());

    // attributes
    for (Attribute att : axis.attributes()) {
      varElem.addContent(ncmlWriter.makeAttributeElement(att));
    }

    if (axis.getRank() == 1) {
      try {
        Element values = ncmlWriter.makeValuesElement(axis, true);
        varElem.addContent(values);
      } catch (IOException e) {
        String message = String.format("Couldn't read values for %s. Omitting  element.", axis.getFullName());
        logger.warn(message, e);
      }
    }

    return varElem;
  }

  // display name plus the dimensions
  private String getShapeString(int[] shape) {
    StringBuilder buf = new StringBuilder();
    for (int i = 0; i < shape.length; i++) {
      if (i != 0)
        buf.append(" ");
      buf.append(shape[i]);
    }
    return buf.toString();
  }


  private Element writeBoundingBox(LatLonRect bb) {

    Element bbElem = new Element("LatLonBox");
    // LatLonPoint llpt = bb.getLowerLeftPoint();
    // LatLonPoint urpt = bb.getUpperRightPoint();

    // bbElem.addContent(new Element("west").addContent(ucar.unidata.util.Format.dfrac(llpt.getLongitude(), 4)));
    bbElem.addContent(new Element("west").addContent(ucar.unidata.util.Format.dfrac(bb.getLonMin(), 4)));
    // bbElem.addContent(new Element("east").addContent(ucar.unidata.util.Format.dfrac(urpt.getLongitude(), 4)));
    bbElem.addContent(new Element("east").addContent(ucar.unidata.util.Format.dfrac(bb.getLonMax(), 4)));
    // bbElem.addContent(new Element("south").addContent(ucar.unidata.util.Format.dfrac(llpt.getLatitude(), 4)));
    bbElem.addContent(new Element("south").addContent(ucar.unidata.util.Format.dfrac(bb.getLatMin(), 4)));
    // bbElem.addContent(new Element("north").addContent(ucar.unidata.util.Format.dfrac(urpt.getLatitude(), 4)));
    bbElem.addContent(new Element("north").addContent(ucar.unidata.util.Format.dfrac(bb.getLatMax(), 4)));

    return bbElem;

  }

  private Element writeGridSet(GridDataset.Gridset gridset) {
    Element csElem = new Element("gridSet");
    GridCoordSystem cs = gridset.getGeoCoordSystem();
    csElem.setAttribute("name", cs.getName());

    ProjectionRect rect = cs.getBoundingBox();
    Element projBBOX = new Element("projectionBox");
    Element minx = new Element("minx");
    minx.addContent(Double.valueOf(rect.getMinX()).toString());
    projBBOX.addContent(minx);
    Element maxx = new Element("maxx");
    maxx.addContent(Double.valueOf(rect.getMaxX()).toString());
    projBBOX.addContent(maxx);
    Element miny = new Element("miny");
    miny.addContent(Double.valueOf(rect.getMinY()).toString());
    projBBOX.addContent(miny);
    Element maxy = new Element("maxy");
    maxy.addContent(Double.valueOf(rect.getMaxY()).toString());
    projBBOX.addContent(maxy);

    csElem.addContent(projBBOX);

    for (CoordinateAxis axis : cs.getCoordinateAxes()) {
      Element axisElem = new Element("axisRef");
      axisElem.setAttribute("name", axis.getFullName());
      csElem.addContent(axisElem);
    }

    for (CoordinateTransform ct : cs.getCoordinateTransforms()) {
      Element elem = new Element("coordTransRef");
      elem.setAttribute("name", ct.getName());
      csElem.addContent(elem);
    }

    List grids = gridset.getGrids();
    Collections.sort(grids);
    for (GridDatatype grid : grids) {
      csElem.addContent(writeGrid(grid));
    }

    return csElem;
  }

  /*
   * private Element writeCoordSys(GridCoordSystem cs) {
   * Element csElem = new Element("coordSys");
   * csElem.setAttribute("name", cs.getName());
   * List axes = cs.getCoordinateAxes();
   * for (int i = 0; i < axes.size(); i++) {
   * CoordinateAxis axis = (CoordinateAxis) axes.get(i);
   * Element axisElem = new Element("axisRef");
   * axisElem.setAttribute("name", axis.getName());
   * csElem.addContent(axisElem);
   * }
   * List cts = cs.getCoordinateTransforms();
   * for (int j = 0; j < cts.size(); j++) {
   * CoordinateTransform ct = (CoordinateTransform) cts.get(j);
   * Element elem = new Element("coordTransRef");
   * elem.setAttribute("name", ct.getName());
   * csElem.addContent(elem);
   * }
   * return csElem;
   * }
   */

  private Element writeCoordTransform(CoordinateTransform ct) {
    Element ctElem = new Element("coordTransform");
    ctElem.setAttribute("name", ct.getName());
    ctElem.setAttribute("transformType", ct.getTransformType().toString());
    for (Parameter param : ct.getParameters()) {
      Element pElem = new Element("parameter");
      pElem.setAttribute("name", param.getName());
      pElem.setAttribute("value", param.getStringValue());
      ctElem.addContent(pElem);
    }
    return ctElem;
  }

  private Element writeGrid(GridDatatype grid) {
    NcmlWriter ncmlWriter = new NcmlWriter();

    Element varElem = new Element("grid");
    varElem.setAttribute("name", grid.getFullName());

    String desc = grid.getDescription() != null ? grid.getDescription() : "No description";
    varElem.setAttribute("desc", desc);

    StringBuilder buff = new StringBuilder();
    List dims = grid.getDimensions();
    for (int i = 0; i < dims.size(); i++) {
      Dimension dim = (Dimension) dims.get(i);
      if (i > 0)
        buff.append(" ");
      if (dim.isShared())
        buff.append(dim.getShortName());
      else
        buff.append(dim.getLength());
    }
    if (buff.length() > 0)
      varElem.setAttribute("shape", buff.toString());

    DataType dt = grid.getDataType();
    if (dt != null)
      varElem.setAttribute("type", dt.toString());

    // GridCoordSystem cs = grid.getCoordinateSystem();
    // varElem.setAttribute("coordSys", cs.getName());

    // attributes
    for (ucar.nc2.Attribute att : grid.getAttributes()) {
      varElem.addContent(ncmlWriter.makeAttributeElement(att));
    }

    return varElem;
  }

  // sort by domain size, then name
  private static class GridSetComparator implements Comparator {

    public int compare(GridDataset.Gridset gridset1, GridDataset.Gridset gridset2) {
      GridCoordSystem cs1 = gridset1.getGeoCoordSystem();
      GridCoordSystem cs2 = gridset2.getGeoCoordSystem();
      if (cs1.getDomain().size() != cs2.getDomain().size())
        return cs1.getDomain().size() - cs2.getDomain().size();
      return cs1.getName().compareTo(cs2.getName());
    }
  }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy