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.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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.ncml.NcMLWriter;
import ucar.nc2.time.CalendarDate;
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();
Collections.sort(gridSets, 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();
Collections.sort(grids, 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();
/* System.out.println(" grid "+grid.getName()
+" time="+(time == null ? " null" : time.hashCode())
+" vert="+(vert == null ? " null" : vert.hashCode())); */
//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.getAttributes())
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();
for (CoordinateAxis axe : gcs.getCoordinateAxes())
axesHash.add(axe);
}
List list = Arrays.asList((CoordinateAxis[]) axesHash.toArray( new CoordinateAxis[ axesHash.size()]));
Collections.sort(list);
return list;
}
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();
for (CoordinateTransform axe : gcs.getCoordinateTransforms())
ctHash.add(axe);
}
List list = Arrays.asList((CoordinateTransform[]) ctHash.toArray( new CoordinateTransform[ ctHash.size()]));
Collections.sort(list);
return list;
}
/* 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.getAttributes()) {
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());
}
}
/**
* debug
*
* @param args ignored
* @throws java.io.IOException on io error
*/
public static void main(String args[]) throws IOException {
String url = "cdmremote:http://localhost:8080/thredds/cdmremote/grib/NCDC/CFSR/NCDC-CFSR/PGB-LatLon0p5";
GridDataset ncd = ucar.nc2.dt.grid.GridDataset.open(url);
GridDatasetInfo info = new GridDatasetInfo(ncd, null);
FileOutputStream fos2 = new FileOutputStream("C:/tmp2/gridInfo.xml");
info.writeXML(info.makeGridForm(), fos2);
fos2.close();
String infoString = info.writeXML(info.makeGridForm());
System.out.println(infoString);
}
}