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

ucar.nc2.ft2.coverage.adapter.DtCoverageCSBuilder 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.ft2.coverage.adapter;

import com.beust.jcommander.internal.Lists;
import ucar.nc2.Dimension;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.FeatureType;
import ucar.nc2.dataset.*;
import ucar.nc2.units.SimpleUnit;
import ucar.unidata.geoloc.ProjectionImpl;
import ucar.unidata.geoloc.projection.RotatedPole;

import java.util.*;

/**
 * Coverage CS classification and builder, using ucar.nc2.dataset.CoordinateSystem
 *
 * @author caron
 * @since 5/26/2015
 */
public class DtCoverageCSBuilder {

  // classify based on largest coordinate system
  public static DtCoverageCSBuilder classify(NetcdfDataset ds, Formatter errlog) {
    if (errlog != null) errlog.format("CoverageFactory for '%s'%n", ds.getLocation());

    // sort by largest size first
    List css = new ArrayList<>(ds.getCoordinateSystems());
    Collections.sort(css, (o1, o2) -> o2.getCoordinateAxes().size() - o1.getCoordinateAxes().size());

    DtCoverageCSBuilder builder = null;
    for (CoordinateSystem cs : css) {
      builder = new DtCoverageCSBuilder(ds, cs, errlog);
      if (builder.type != null) break;
    }
    if (builder == null) return null;
    if (errlog != null) errlog.format("coverage = %s%n", builder.type);
    return builder;
  }

  public static String describe(NetcdfDataset ds, Formatter errlog) {
    DtCoverageCSBuilder fac = classify(ds, errlog);
    return (fac == null || fac.type == null) ? "" : fac.showSummary();
  }

  public static String describe(NetcdfDataset ds, CoordinateSystem cs, Formatter errlog) {
    DtCoverageCSBuilder fac = new DtCoverageCSBuilder(ds, cs, errlog);
    return fac.type == null ? "" : fac.showSummary();
  }

  ////////////////////////////////////////////////////////////////////////////////////
  FeatureType type;

  boolean isLatLon;
  CoordinateAxis xaxis, yaxis, timeAxis;
  CoordinateAxis1D vertAxis, ensAxis, timeOffsetAxis;
  CoordinateAxis1DTime rtAxis;
  List independentAxes;
  List otherAxes;
  List allAxes;
  List coordTransforms;
  ProjectionImpl orgProj;

  DtCoverageCSBuilder(NetcdfDataset ds, CoordinateSystem cs, Formatter errlog) {

    // must be at least 2 dimensions
    if (cs.getRankDomain() < 2) {
      if (errlog != null) errlog.format("CoordinateSystem '%s': domain rank < 2%n", cs.getName());
      return;
    }

    //////////////////////////////////////////////////////////////
    // horiz
    // must be lat/lon or have x,y and projection
    if (!cs.isLatLon()) {
      // do check for GeoXY
      if ((cs.getXaxis() == null) || (cs.getYaxis() == null)) {
        if (errlog != null) errlog.format("%s: NO Lat,Lon or X,Y axis%n", cs.getName());
        return;
      }
      if (null == cs.getProjection()) {
        if (errlog != null) errlog.format("%s: NO projection found%n", cs.getName());
        return;
      }
    }

    // obtain the x,y or lat/lon axes. x,y normally must be convertible to km
    if (cs.isGeoXY()) {
      xaxis = cs.getXaxis();
      yaxis = cs.getYaxis();

      ProjectionImpl p = cs.getProjection();
      if (!(p instanceof RotatedPole)) {
        if (!SimpleUnit.kmUnit.isCompatible(xaxis.getUnitsString())) {
          if (errlog != null) errlog.format("%s: X axis units are not convertible to km%n", cs.getName());
          //return false;
        }
        if (!SimpleUnit.kmUnit.isCompatible(yaxis.getUnitsString())) {
          if (errlog != null) errlog.format("%s: Y axis units are not convertible to km%n", cs.getName());
          //return false;
        }
      }
    } else {
      xaxis = cs.getLonAxis();
      yaxis = cs.getLatAxis();
      isLatLon = true;
    }

    // check x,y rank <= 2
    if ((xaxis.getRank() > 2) || (yaxis.getRank() > 2)) {
      if (errlog != null) errlog.format("%s: X and Y axis rank must be <= 2%n", cs.getName());
      return;
    }

    // check x,y with size 1
    if ((xaxis.getSize() < 2) || (yaxis.getSize() < 2)) {
      if (errlog != null) errlog.format("%s: X and Y axis size must be >= 2%n", cs.getName());
      return;
    }

    // check that the x,y have at least 2 dimensions between them ( this eliminates point data)
    int xyDomainSize = CoordinateSystem.countDomain(new CoordinateAxis[]{xaxis, yaxis});
    if (xyDomainSize < 2) {
      if (errlog != null) errlog.format("%s: X and Y axis must have 2 or more dimensions%n", cs.getName());
      return;
    }

    allAxes = new ArrayList<>(cs.getCoordinateAxes());
    Collections.sort(allAxes, new CoordinateAxis.AxisComparator()); // canonical ordering of axes

    independentAxes = new ArrayList<>();
    otherAxes = new ArrayList<>();
    for (CoordinateAxis axis : cs.getCoordinateAxes()) {
      // skip x,y if no projection
      if ((axis.getAxisType() == AxisType.GeoX || axis.getAxisType() == AxisType.GeoY) && isLatLon) continue;
      if (axis.isIndependentCoordinate()) independentAxes.add(axis);
      else otherAxes.add(axis);
    }
    Collections.sort(independentAxes, (o1, o2) -> {
      AxisType t1 = o1.getAxisType();
      AxisType t2 = o2.getAxisType();
      if (t1 != null && t2 != null)
        return t1.axisOrder() - t2.axisOrder();
      return (t1 == null) ? ((t2 == null) ? 0 : -1) : 1;
    });

    //////////////////////////////////////////////////////////////
    // vert
    CoordinateAxis zAxis = cs.getHeightAxis();
    if ((zAxis == null) || (zAxis.getRank() > 1)) {
      if (cs.getPressureAxis() != null) zAxis = cs.getPressureAxis();
    }
    if ((zAxis == null) || (zAxis.getRank() > 1)) {
      if (cs.getZaxis() != null) zAxis = cs.getZaxis();
    }
    if (zAxis != null) {
      if (zAxis instanceof CoordinateAxis1D)
        vertAxis = (CoordinateAxis1D) zAxis;
    }

    //////////////////////////////////////////////////////////////
    // time
    CoordinateAxis rt = cs.findAxis(AxisType.RunTime);
    if (rt != null) {
      if (!rt.isScalar() && !(rt instanceof CoordinateAxis1D)) {   // A runtime axis must be scalar or one-dimensional
        if (errlog != null) errlog.format("%s: RunTime axis must be 1D or scalar%n", cs.getName());
        return;
      }
      if (!(rt instanceof CoordinateAxis1DTime)) {    // convert to CoordinateAxis1DTime
        try {
          rtAxis = CoordinateAxis1DTime.factory(ds, rt, errlog);
          int index = allAxes.indexOf(rt); // replace
          allAxes.set(index, rtAxis);
        } catch (Exception e) {
          if (errlog != null)
            errlog.format("%s: Error reading runtime coord= %s err= %s%n", rt.getDatasetLocation(), rt.getFullName(), e.getMessage());
          return;
        }
      } else {
        rtAxis = (CoordinateAxis1DTime) rt;
      }
    }

    CoordinateAxis t = cs.getTaxis();
    if ((t != null) && t.getRank() > 1) {  // If time axis is two-dimensional...
      if (rtAxis != null && rtAxis.getRank() == 1) {
        // time first dimension must agree with runtime
        if (!rtAxis.getDimension(0).equals(t.getDimension(0))) {
          if (errlog != null) errlog.format("%s: 2D Time axis first dimension must be runtime%n", cs.getName());
          return;
        }
      }
    }

    if (t != null) {
      if (t instanceof CoordinateAxis1D && !(t instanceof CoordinateAxis1DTime)) {  // convert time axis into CoordinateAxis1DTime if possible
        try {
          timeAxis = CoordinateAxis1DTime.factory(ds, t, errlog);
          int index = allAxes.indexOf(t); // replace
          allAxes.set(index, timeAxis);
        } catch (Exception e) {
          if (errlog != null)
            errlog.format("%s: Error reading time coord= %s err= %s%n", t.getDatasetLocation(), t.getFullName(), e.getMessage());
          return;
        }
      } else {
        timeAxis = t;
      }
    }

    CoordinateAxis toAxis = cs.findAxis(AxisType.TimeOffset);
    if (toAxis != null) {
      if (toAxis.getRank() == 1)
        timeOffsetAxis = (CoordinateAxis1D) toAxis;
    }

    if (t == null && rtAxis != null && timeOffsetAxis != null) {
      // LOOK create time coord ??
    }

    CoordinateAxis eAxis = cs.findAxis(AxisType.Ensemble);
    if (eAxis != null) {
      if (eAxis instanceof CoordinateAxis1D)
        ensAxis = (CoordinateAxis1D) eAxis;
    }

    this.type = classify();
    this.coordTransforms = new ArrayList<>(cs.getCoordinateTransforms());
    this.orgProj = cs.getProjection();
  }

  private FeatureType classify () {

    // now to classify
    boolean is2Dtime = (rtAxis != null) && (timeOffsetAxis != null || (timeAxis != null && timeAxis.getRank() == 2));
    if (is2Dtime) {
      return FeatureType.FMRC;   // LOOK this would allow 2d horiz
    }

    boolean is2Dhoriz = isLatLon && (xaxis.getRank() == 2) && (yaxis.getRank() == 2);
    if (is2Dhoriz) {
      Set xyDomain = CoordinateSystem.makeDomain(Lists.newArrayList(xaxis, yaxis));
      if (timeAxis != null && CoordinateSystem.isSubset(timeAxis.getDimensionsAll(), xyDomain))
        return FeatureType.SWATH;   // LOOK prob not exactly right
      else
        return FeatureType.CURVILINEAR;
    }

    // what makes it a grid?
    // each dimension must have its own coordinate variable
    Set indDimensions = CoordinateSystem.makeDomain(independentAxes);
    Set allDimensions = CoordinateSystem.makeDomain(allAxes);
    if (indDimensions.size() == allDimensions.size()) {
      return FeatureType.GRID;
    }

    // default
    return FeatureType.COVERAGE;
  }

  public FeatureType getCoverageType() {
    return type;
  }

  public DtCoverageCS makeCoordSys() {
    if (type == null) return null;

    switch (type) {
      case GRID:
        return new GridCS(this);
      case FMRC:
        return new FmrcCS(this);
      case CURVILINEAR:
        return new CurvilinearCS(this);
      case SWATH:
        return new SwathCS(this);
    }
    return new DtCoverageCS(this);
  }

  @Override
  public String toString() {
    Formatter f2 = new Formatter();
    f2.format("%s", type == null ? "" : type.toString());
    f2.format("%n xAxis=  %s", xaxis == null ? "" : xaxis.getNameAndDimensions());
    f2.format("%n yAxis=  %s", yaxis == null ? "" : yaxis.getNameAndDimensions());
    f2.format("%n zAxis=  %s", vertAxis == null ? "" : vertAxis.getNameAndDimensions());
    f2.format("%n tAxis=  %s", timeAxis == null ? "" : timeAxis.getNameAndDimensions());
    f2.format("%n rtAxis= %s", rtAxis == null ? "" : rtAxis.getNameAndDimensions());
    f2.format("%n toAxis= %s", timeOffsetAxis == null ? "" : timeOffsetAxis.getNameAndDimensions());
    f2.format("%n ensAxis=%s", ensAxis == null ? "" : ensAxis.getNameAndDimensions());
    if (type == null) return f2.toString();

    f2.format("%n%n independentAxes=(");
    for (CoordinateAxis axis : independentAxes)
      f2.format("%s, ", axis.getShortName());
    f2.format(") {");
    for (Dimension dim : CoordinateSystem.makeDomain(independentAxes))
      f2.format("%s, ", dim.getShortName());
    f2.format("}");
    f2.format("%n otherAxes=(");
    for (CoordinateAxis axis : otherAxes)
      f2.format("%s, ", axis.getShortName());
    f2.format(") {");
    for (Dimension dim : CoordinateSystem.makeDomain(otherAxes))
      f2.format("%s, ", dim.getShortName());
    f2.format("}");
    f2.format("%n allAxes=(");
    for (CoordinateAxis axis : allAxes)
      f2.format("%s, ", axis.getShortName());
    f2.format(") {");
    for (Dimension dim : CoordinateSystem.makeDomain(allAxes))
      f2.format("%s, ", dim.getShortName());
    f2.format("}%n");

    return f2.toString();
  }

  public String showSummary() {
    if (type == null) return "";

    Formatter f2 = new Formatter();
    f2.format("%s", type.toString());

    f2.format("(");
    int count = 0;
    for (CoordinateAxis axis : independentAxes) {
      if (count++ > 0) f2.format(",");
      f2.format("%s", axis.getAxisType() == null ? axis.getShortName() : axis.getAxisType().getCFAxisName());
    }
    f2.format(")");

    if (otherAxes.size() > 0) {
      f2.format(": ");
      count = 0;
      for (CoordinateAxis axis : otherAxes) {
        if (count++ > 0) f2.format(",");
        f2.format("%s", axis.getShortName());
      }
    }
    return f2.toString();
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy