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

ucar.nc2.internal.dataset.conv.ADASConvention Maven / Gradle / Ivy

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

package ucar.nc2.internal.dataset.conv;

import java.io.IOException;
import java.util.Optional;
import ucar.ma2.Array;
import ucar.ma2.ArrayFloat;
import ucar.ma2.DataType;
import ucar.ma2.Index;
import ucar.nc2.Attribute;
import ucar.nc2.Variable;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants.CF;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.dataset.CoordinateAxis;
import ucar.nc2.dataset.CoordinateAxis1D;
import ucar.nc2.dataset.CoordinateTransform;
import ucar.nc2.dataset.NetcdfDataset;
import ucar.nc2.dataset.ProjectionCT;
import ucar.nc2.dataset.VariableDS;
import ucar.nc2.dataset.spi.CoordSystemBuilderFactory;
import ucar.nc2.internal.dataset.CoordSystemBuilder;
import ucar.nc2.units.SimpleUnit;
import ucar.nc2.util.CancelTask;
import ucar.unidata.geoloc.LatLonPoint;
import ucar.unidata.geoloc.Projection;
import ucar.unidata.geoloc.ProjectionImpl;
import ucar.unidata.geoloc.ProjectionPoint;
import ucar.unidata.geoloc.projection.LambertConformal;

/** ADAS netcdf files. Not finished because we dont have any tests files. */
public class ADASConvention extends CoordSystemBuilder {
  private static final String CONVENTION_NAME = "ARPS/ADAS";

  // private double originX = 0.0, originY = 0.0;
  private ProjectionCT projCT;
  private static final boolean debugProj = false;

  ADASConvention(NetcdfDataset.Builder datasetBuilder) {
    super(datasetBuilder);
    this.conventionName = CONVENTION_NAME;
  }

  @Override
  protected void augmentDataset(CancelTask cancelTask) throws IOException {
    if (!rootGroup.findVariableLocal("x").isPresent()) {
      return; // check if its already been done - aggregating enhanced datasets.
    }

    // old way without attributes
    Attribute att = rootGroup.getAttributeContainer().findAttribute("MAPPROJ");
    int projType = att.getNumericValue().intValue();

    double lat1 = rootGroup.getAttributeContainer().findAttributeDouble("TRUELAT1", Double.NaN);
    double lat2 = rootGroup.getAttributeContainer().findAttributeDouble("TRUELAT2", Double.NaN);
    double lat_origin = lat1;
    double lon_origin = rootGroup.getAttributeContainer().findAttributeDouble("TRUELON", Double.NaN);
    double false_easting = 0.0;
    double false_northing = 0.0;

    // new way with attributes
    String projName = rootGroup.getAttributeContainer().findAttributeString(CF.GRID_MAPPING_NAME, null);
    if (projName != null) {
      projName = projName.trim();
      lat_origin = rootGroup.getAttributeContainer().findAttributeDouble("latitude_of_projection_origin", Double.NaN);
      lon_origin = rootGroup.getAttributeContainer().findAttributeDouble("longitude_of_central_meridian", Double.NaN);
      false_easting = rootGroup.getAttributeContainer().findAttributeDouble("false_easting", 0.0);
      false_northing = rootGroup.getAttributeContainer().findAttributeDouble("false_northing", 0.0);

      Attribute att2 = rootGroup.getAttributeContainer().findAttributeIgnoreCase("standard_parallel");
      if (att2 != null) {
        lat1 = att2.getNumericValue().doubleValue();
        lat2 = (att2.getLength() > 1) ? att2.getNumericValue(1).doubleValue() : lat1;
      }
    } else {
      if (projType == 2)
        projName = "lambert_conformal_conic";
    }

    Optional> coordOpt = rootGroup.findVariableLocal("x_stag");
    if (coordOpt.isPresent()) {
      Variable.Builder coord = coordOpt.get();
      if (!Double.isNaN(false_easting) || !Double.isNaN(false_northing)) {
        String units = coord.getAttributeContainer().findAttributeString(CDM.UNITS, null);
        double scalef = 1.0;
        try {
          scalef = SimpleUnit.getConversionFactor(units, "km");
        } catch (IllegalArgumentException e) {
          log.error(units + " not convertible to km");
        }
        false_easting *= scalef;
        false_northing *= scalef;
      }
    }

    ProjectionImpl proj;
    if ("lambert_conformal_conic".equalsIgnoreCase(projName)) {
      proj = new LambertConformal(lat_origin, lon_origin, lat1, lat2, false_easting, false_northing);
      projCT = new ProjectionCT("Projection", "FGDC", proj);
      if (false_easting == 0.0)
        calcCenterPoints(proj); // old way
    } else {
      parseInfo.format("ERROR: unknown projection type = %s%n", projName);
    }

    if (projCT != null) {
      VariableDS.Builder v = makeCoordinateTransformVariable(projCT);
      v.addAttribute(new Attribute(_Coordinate.AxisTypes, "GeoX GeoY"));
      rootGroup.addVariable(v);
    }

    makeCoordAxis("x");
    makeCoordAxis("y");
    makeCoordAxis("z");

    rootGroup.findVariableLocal("ZPSOIL")
        .ifPresent(vb -> vb.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.GeoZ.toString())));
  }

  // old way without attributes
  private void calcCenterPoints(Projection proj) throws IOException {
    double lat_check = rootGroup.getAttributeContainer().findAttributeDouble("CTRLAT", Double.NaN);
    double lon_check = rootGroup.getAttributeContainer().findAttributeDouble("CTRLON", Double.NaN);

    LatLonPoint lpt0 = LatLonPoint.create(lat_check, lon_check);
    ProjectionPoint ppt0 = proj.latLonToProj(lpt0);

    VariableDS.Builder xstag = (VariableDS.Builder) rootGroup.findVariableLocal("x_stag")
        .orElseThrow(() -> new IllegalStateException("Must have x_stag Variable"));
    Variable xstagOrg = xstag.orgVar;
    int nxpts = (int) xstagOrg.getSize();
    ArrayFloat.D1 xstagData = (ArrayFloat.D1) xstagOrg.read();
    float center_x = xstagData.get(nxpts - 1);
    double false_easting = center_x / 2000 - ppt0.getX() * 1000.0;

    VariableDS.Builder ystag = (VariableDS.Builder) rootGroup.findVariableLocal("y_stag")
        .orElseThrow(() -> new IllegalStateException("Must have y_stag Variable"));
    Variable ystagOrg = ystag.orgVar;
    int nypts = (int) ystagOrg.getSize();
    ArrayFloat.D1 ystagData = (ArrayFloat.D1) ystagOrg.read();
    float center_y = ystagData.get(nypts - 1);
    double false_northing = center_y / 2000 - ppt0.getY() * 1000.0;
    log.debug("false easting/northing= {} {} ", false_easting, false_northing);

    double dx = rootGroup.getAttributeContainer().findAttributeDouble("DX", Double.NaN);
    double dy = rootGroup.getAttributeContainer().findAttributeDouble("DY", Double.NaN);

    double w = dx * (nxpts - 1);
    double h = dy * (nypts - 1);
    double startx = ppt0.getX() * 1000.0 - w / 2;
    double starty = ppt0.getY() * 1000.0 - h / 2;

    xstag.setAutoGen(startx, dx);
    ystag.setAutoGen(starty, dy);
  }

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

  @Override
  protected void makeCoordinateTransforms() {
    if (projCT != null) {
      VarProcess vp = findVarProcess(projCT.getName(), null);
      vp.isCoordinateTransform = true;
      vp.ct = CoordinateTransform.builder().setPreBuilt(projCT);
    }
    super.makeCoordinateTransforms();
  }

  @Override
  protected AxisType getAxisType(VariableDS.Builder vb) {
    String vname = vb.shortName;

    if (vname.equalsIgnoreCase("x") || vname.equalsIgnoreCase("x_stag"))
      return AxisType.GeoX;

    if (vname.equalsIgnoreCase("lon"))
      return AxisType.Lon;

    if (vname.equalsIgnoreCase("y") || vname.equalsIgnoreCase("y_stag"))
      return AxisType.GeoY;

    if (vname.equalsIgnoreCase("lat"))
      return AxisType.Lat;

    if (vname.equalsIgnoreCase("z") || vname.equalsIgnoreCase("z_stag"))
      return AxisType.GeoZ;

    if (vname.equalsIgnoreCase("Z"))
      return AxisType.Height;

    if (vname.equalsIgnoreCase("time"))
      return AxisType.Time;

    String unit = vb.getUnits();
    if (unit != null) {
      if (SimpleUnit.isCompatible("millibar", unit))
        return AxisType.Pressure;

      if (SimpleUnit.isCompatible("m", unit))
        return AxisType.Height;
    }


    return null;
  }

  /**
   * Does increasing values of Z go vertical up?
   *
   * @param v for this axis
   * @return "up" if this is a Vertical (z) coordinate axis which goes up as coords get bigger,
   *         else return "down"
   */
  public String getZisPositive(CoordinateAxis v) {
    return "down"; // eta coords decrease upward
  }

  private void makeCoordAxis(String axisName) throws IOException {
    String name = axisName + "_stag";
    if (!rootGroup.findVariableLocal(name).isPresent()) {
      return;
    }
    VariableDS.Builder stagV = (VariableDS.Builder) rootGroup.findVariableLocal(name).get();
    Array data_stag = stagV.orgVar.read();
    int n = (int) data_stag.getSize() - 1;
    DataType dt = DataType.getType(data_stag);
    Array data = Array.factory(dt, new int[] {n});
    Index stagIndex = data_stag.getIndex();
    Index dataIndex = data.getIndex();
    for (int i = 0; i < n; i++) {
      double val = data_stag.getDouble(stagIndex.set(i)) + data_stag.getDouble(stagIndex.set(i + 1));
      data.setDouble(dataIndex.set(i), 0.5 * val);
    }

    DataType dtype = DataType.getType(data);
    String units = stagV.getAttributeContainer().findAttributeString(CDM.UNITS, "m");
    CoordinateAxis.Builder cb = CoordinateAxis1D.builder().setName(axisName).setDataType(dtype)
        .setParentGroupBuilder(rootGroup).setDimensionsByName(axisName).setUnits(units)
        .setDesc("synthesized non-staggered " + axisName + " coordinate");
    cb.setCachedData(data, true);
    datasetBuilder.replaceCoordinateAxis(rootGroup, cb);
  }

  public static class Factory implements CoordSystemBuilderFactory {
    @Override
    public String getConventionName() {
      return CONVENTION_NAME;
    }

    @Override
    public CoordSystemBuilder open(NetcdfDataset.Builder datasetBuilder) {
      return new ADASConvention(datasetBuilder);
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy