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

ucar.nc2.dt.radial.Nexrad2RadialAdapter 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.radial;

import ucar.nc2.*;
import ucar.nc2.dataset.*;
import ucar.nc2.constants.*;
import ucar.nc2.dt.*;
import ucar.nc2.ft.FeatureDataset;
import ucar.nc2.time.CalendarDateUnit;
import ucar.nc2.units.DateFormatter;
import ucar.nc2.units.DateUnit;
import ucar.ma2.*;
import ucar.unidata.geoloc.EarthLocation;
import ucar.unidata.geoloc.LatLonPoint;
import ucar.unidata.geoloc.LatLonRect;
import ucar.unidata.geoloc.Earth;
import java.io.IOException;
import java.util.*;


/**
 * Make a NEXRAD Level 2 NetcdfDataset into a RadialDataset.
 *
 * @author yuan
 */

public class Nexrad2RadialAdapter extends AbstractRadialAdapter {
  private NetcdfDataset ds;
  double latv, lonv, elev;
  DateFormatter formatter = new DateFormatter();


  static private boolean isNEXRAD2Format(String format) {
    // somewhat duplicated in Nexrad2IOServiceProvider - so if chaing something here, also
    // look in cdm-radial module's Nexrad2IOServiceProvider.isNEXRAD2Format
    // TODO: find a home for this method to be shared
    return format != null && (format.equals("ARCHIVE2") || format.startsWith("AR2V"));
    // log message about Trying to handle unknown but valid-looking format handled in Nexrad2IOServiceProvider
  }

  /////////////////////////////////////////////////
  public Object isMine(FeatureType wantFeatureType, NetcdfDataset ncd, Formatter errlog) {
    String convention = ncd.getRootGroup().findAttributeString("Conventions", null);
    if (_Coordinate.Convention.equals(convention)) {
      String format = ncd.getRootGroup().findAttributeString("Format", null);
      if (format != null && (isNEXRAD2Format(format) || format.equals("CINRAD-SA"))) {
        return this;
      }
    }
    return null;
  }

  public FeatureDataset open(FeatureType ftype, NetcdfDataset ncd, Object analysis, ucar.nc2.util.CancelTask task,
      Formatter errlog) {
    return new Nexrad2RadialAdapter(ncd);
  }

  public FeatureType getScientificDataType() {
    return FeatureType.RADIAL;
  }

  // needed for FeatureDatasetFactory
  public Nexrad2RadialAdapter() {}

  /**
   * Constructor.
   *
   * @param ds must be from nexrad2 IOSP
   */
  public Nexrad2RadialAdapter(NetcdfDataset ds) {
    super(ds);
    this.ds = ds;
    desc = "Nexrad 2 radar dataset";

    setEarthLocation();
    try {
      setTimeUnits();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    setStartDate();
    setEndDate();
    setBoundingBox();
  }

  protected void setBoundingBox() {
    LatLonRect bb;

    if (origin == null)
      return;

    double dLat = Math.toDegrees(getMaximumRadialDist() / Earth.WGS84_EARTH_RADIUS_METERS);
    double latRadians = Math.toRadians(origin.getLatitude());
    double dLon = dLat * Math.cos(latRadians);

    double lat1 = origin.getLatitude() - dLat / 2;
    double lon1 = origin.getLongitude() - dLon / 2;
    bb = new LatLonRect(LatLonPoint.create(lat1, lon1), dLat, dLon);

    boundingBox = bb;
  }

  double getMaximumRadialDist() {
    double maxdist = 0.0;

    for (VariableSimpleIF dataVariable : dataVariables) {
      RadialVariable rv = (RadialVariable) dataVariable;
      Sweep sp = rv.getSweep(0);
      double dist = sp.getGateNumber() * sp.getGateSize();

      if (dist > maxdist) {
        maxdist = dist;
      }
    }

    return maxdist;
  }

  protected void setEarthLocation() {
    Attribute ga = ds.findGlobalAttribute("StationLatitude");
    if (ga != null)
      latv = ga.getNumericValue().doubleValue();
    else
      latv = 0.0;

    ga = ds.findGlobalAttribute("StationLongitude");
    if (ga != null)
      lonv = ga.getNumericValue().doubleValue();
    else
      lonv = 0.0;

    ga = ds.findGlobalAttribute("StationElevationInMeters");
    if (ga != null)
      elev = ga.getNumericValue().doubleValue();
    else
      elev = 0.0;

    origin = EarthLocation.create(latv, lonv, elev);
  }

  public ucar.unidata.geoloc.EarthLocation getCommonOrigin() {
    return origin;
  }

  public String getRadarID() {
    Attribute ga = ds.findGlobalAttribute("Station");
    if (ga != null)
      return ga.getStringValue();
    else
      return "XXXX";
  }

  public String getRadarName() {
    Attribute ga = ds.findGlobalAttribute("StationName");
    if (ga != null)
      return ga.getStringValue();
    else
      return "Unknown Station";
  }

  public String getDataFormat() {
    return "Level II";
  }



  public boolean isVolume() {
    return true;
  }

  public boolean isHighResolution(NetcdfDataset nds) {
    // return true;
    Dimension r = nds.findDimension("scanR_HI");
    Dimension v = nds.findDimension("scanV_HI");
    return r != null || v != null;
  }

  public boolean isStationary() {
    return true;
  }

  protected void setTimeUnits() throws Exception {
    for (CoordinateAxis axis : ds.getCoordinateAxes()) {
      if (axis.getAxisType() == AxisType.Time) {
        String units = axis.getUnitsString();
        dateUnits = new DateUnit(units);
        calDateUnits = CalendarDateUnit.of(null, units);
        return;
      }
    }
    parseInfo.append("*** Time Units not Found\n");
  }

  protected void setStartDate() {
    String start_datetime = ds.getRootGroup().findAttributeString("time_coverage_start", null);
    if (start_datetime != null)
      startDate = formatter.getISODate(start_datetime);
    else
      parseInfo.append("*** start_datetime not Found\n");
  }

  protected void setEndDate() {
    String end_datetime = ds.getRootGroup().findAttributeString("time_coverage_end", null);
    if (end_datetime != null)
      endDate = formatter.getISODate(end_datetime);
    else
      parseInfo.append("*** end_datetime not Found\n");
  }

  public void clearDatasetMemory() {
    for (VariableSimpleIF rvar : getDataVariables()) {
      RadialVariable radVar = (RadialVariable) rvar;
      radVar.clearVariableMemory();
    }
  }

  public void getRadialsNum() {}

  protected void addRadialVariable(NetcdfDataset nds, Variable var) {
    RadialVariable rsvar = null;
    String vName = var.getShortName();
    int rnk = var.getRank();

    if (rnk == 3) {
      if (!isHighResolution(nds)) {
        rsvar = makeRadialVariable(nds, var);
      } else {
        if (!vName.endsWith("_HI")) {
          rsvar = makeRadialVariable(nds, var);
        }
      }
    }

    if (rsvar != null)
      dataVariables.add(rsvar);
  }

  protected RadialVariable makeRadialVariable(NetcdfDataset nds, Variable v0) {
    // this function is null in level 2
    return new LevelII2Variable(nds, v0);
  }

  public String getInfo() {
    String sbuff = "LevelII2Dataset\n" + super.getDetailInfo() + "\n\n" + parseInfo;
    return sbuff;
  }


  private class LevelII2Variable extends MyRadialVariableAdapter implements RadialDatasetSweep.RadialVariable {
    int nsweeps;
    int nsweepsHR;
    ArrayList sweeps;

    private LevelII2Variable(NetcdfDataset nds, Variable v0) {
      super(v0.getShortName(), v0);

      nsweepsHR = 0;
      sweeps = new ArrayList<>();
      if (isHighResolution(nds)) {
        String vname = v0.getFullNameEscaped();
        Variable vehr = nds.findVariable(vname + "_HI");

        int[] shape1;
        if (vehr != null) {
          shape1 = vehr.getShape();
          int count1 = vehr.getRank() - 1;
          int ngatesHR = shape1[count1];
          count1--;
          int nraysHR = shape1[count1];
          count1--;
          nsweepsHR = shape1[count1];
          for (int i = 0; i < nsweepsHR; i++)
            sweeps.add(new LevelII2Sweep(vehr, i, nraysHR, ngatesHR));

        }
      }

      int[] shape = v0.getShape();
      int count = v0.getRank() - 1;

      int ngates = shape[count];
      count--;
      int nrays = shape[count];
      count--;
      nsweeps = shape[count];
      for (int i = nsweepsHR; i < (nsweeps + nsweepsHR); i++)
        sweeps.add(new LevelII2Sweep(v0, i, nrays, ngates));
    }

    public String toString() {
      return name;
    }

    public int getNumSweeps() {
      if (isHighResolution(ds)) {
        return nsweepsHR + nsweeps;
      }
      return nsweeps;
    }

    public Sweep getSweep(int sweepNo) {
      return sweeps.get(sweepNo);
    }

    public int getNumRadials() {
      return 0;
    }

    // a 3D array nsweep * nradials * ngates
    // if high resolution data, it will be transfered to the same dimension
    public float[] readAllData() throws IOException {
      Array allData;
      Sweep spn = (Sweep) sweeps.get(sweeps.size() - 1);
      Variable v = spn.getsweepVar();
      float vGateSize = spn.getGateSize();
      allData = v.read();
      if (!isHighResolution(ds))
        return (float[]) allData.get1DJavaArray(float.class);
      else {
        Sweep sp0 = (Sweep) sweeps.get(0);
        Variable v0 = sp0.getsweepVar();
        float v0GateSize = sp0.getGateSize();
        int[] stride;

        if (v0.getShortName().startsWith("Reflect"))
          stride = new int[] {1, 2, 4};
        else
          stride = new int[] {1, 2, 1};

        int[] shape1 = v.getShape();
        int[] shape2 = v0.getShape();
        int shp1 = (shape1[1] * stride[1] > shape2[1]) ? shape2[1] : shape1[1] * stride[1];


        int shp2 = (shape1[2] * stride[2] > shape2[2]) ? shape2[2] : shape1[2] * stride[2];

        int[] shape = {shape2[0], shp1, shp2};
        // this dual pole or new high res
        // where the lower and upper has same gate size, no stride needed
        if (shape2[2] == shape1[2] || v0GateSize == vGateSize) {
          stride = new int[] {1, 2, 1};
          shape[2] = shape1[2];
        }

        int[] origin = {0, 0, 0};

        try {
          Section section = new Section(origin, shape, stride);
          Array hrData = v0.read(section);

          // now append hrData and allData
          float[] fa1 = (float[]) hrData.get1DJavaArray(float.class);
          float[] fa2 = (float[]) allData.get1DJavaArray(float.class);
          float[] fa = new float[fa1.length + fa2.length];
          System.arraycopy(fa1, 0, fa, 0, fa1.length);
          System.arraycopy(fa2, 0, fa, fa1.length, fa2.length);

          return fa;
        } catch (ucar.ma2.InvalidRangeException e) {
          throw new IOException(e);
        }
      }
    }

    public void clearVariableMemory() {
      for (int i = 0; i < nsweeps; i++) {

      }
    }


    //////////////////////////////////////////////////////////////////////
    // Checking all azi to make sure there is no missing data at sweep
    // level, since the coordinate is 1D at this level, this checking also
    // remove those missing radials within a sweep.

    private class LevelII2Sweep implements RadialDatasetSweep.Sweep {
      double meanElevation = Double.NaN;
      double meanAzimuth = Double.NaN;
      int nrays, ngates;
      int sweepno;
      Variable sweepVar;


      LevelII2Sweep(Variable v, int sweepno, int rays, int gates) {
        this.sweepVar = v;
        this.sweepno = sweepno;
        this.nrays = rays;
        this.ngates = gates;
        // ucar.unidata.util.Trace.call2("LevelII2Dataset:testRadialVariable mine");
      }

      public Variable getsweepVar() {
        return sweepVar;
      }

      /* read 2d sweep data nradials * ngates */
      public float[] readData() throws java.io.IOException {

        if (!isHighResolution(ds)) {
          return sweepData(sweepno);
        } else {
          if (sweepno > (nsweepsHR - 1)) {
            int swpNo = sweepno - nsweepsHR;
            return sweepData(swpNo);
          } else {
            return sweepData(sweepno);
          }
        }

      }

      /* read from the radial variable */
      private float[] sweepData(int swpNumber) throws IOException {
        int[] shape = sweepVar.getShape();
        int[] origin = new int[3];

        // init section
        origin[0] = swpNumber;
        shape[0] = 1;

        try {
          Array sweepTmp = sweepVar.read(origin, shape).reduce();
          return (float[]) sweepTmp.get1DJavaArray(Float.TYPE);
        } catch (ucar.ma2.InvalidRangeException e) {
          throw new IOException(e);
        }
      }

      // private Object MUTEX =new Object();
      /* read 1d data ngates */
      public float[] readData(int ray) throws java.io.IOException {
        if (!isHighResolution(ds)) {
          return rayData(sweepno, ray);
        } else {
          if (sweepno >= nsweepsHR) {
            int swpNo = sweepno - (nsweepsHR);
            return rayData(swpNo, ray);
          } else {
            return rayData(sweepno, ray);
          }
        }
      }

      /* read the radial data from the radial variable */
      public float[] rayData(int swpNumber, int ray) throws java.io.IOException {
        int[] shape = sweepVar.getShape();
        int[] origin = new int[3];

        // init section
        origin[0] = swpNumber;
        origin[1] = ray; // shape[1] - numRadial + ray ;
        shape[0] = 1;
        shape[1] = 1;

        try {
          Array sweepTmp = sweepVar.read(origin, shape).reduce();
          return (float[]) sweepTmp.get1DJavaArray(Float.TYPE);
        } catch (ucar.ma2.InvalidRangeException e) {
          throw new IOException(e);
        }
      }


      public void setMeanElevation() {
        String eleName = getRadialVarCoordinateName("elevation", sweepVar.getShortName());

        if (!isHighResolution(ds)) {
          setMeanEle(eleName, sweepno);
        } else {
          if (sweepno >= nsweepsHR) {
            int swpNo = sweepno - (nsweepsHR);
            setMeanEle(eleName, swpNo);
          } else {
            setMeanEle(eleName + "_HI", sweepno);
          }
        }
      }

      private void setMeanEle(String elevName, int swpNumber) {
        float sum = 0;
        int sumSize = 0;

        try {
          float[] eleArray = getEle(elevName, swpNumber);
          for (float v : eleArray) {
            if (!Float.isNaN(v)) {
              sum += v;
              sumSize++;
            }
          }
          if (sumSize > 0)
            meanElevation = sum / sumSize;
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      public float getMeanElevation() {
        if (Double.isNaN(meanElevation))
          setMeanElevation();
        return (float) meanElevation;
      }

      public double meanDouble(Array a) {
        double sum = 0;
        int size = 0;

        IndexIterator iterA = a.getIndexIterator();
        while (iterA.hasNext()) {
          double s = iterA.getDoubleNext();

          if (!Double.isNaN(s)) {
            sum += s;
            size++;
          }
        }
        if (size > 0)
          return sum / size;
        else
          return Double.POSITIVE_INFINITY;
      }

      public int getGateNumber() {
        return ngates;
      }

      public int getRadialNumber() {
        return nrays;
      }


      public RadialDatasetSweep.Type getType() {
        return null;
      }

      public ucar.unidata.geoloc.EarthLocation getOrigin(int ray) {
        return origin;
      }

      public Date getStartingTime() {
        return startDate;
      }

      public Date getEndingTime() {
        return endDate;
      }

      public int getSweepIndex() {
        return sweepno;
      }


      public void setMeanAzimuth() {
        String aziName = getRadialVarCoordinateName("azimuth", sweepVar.getShortName());

        if (!isHighResolution(ds)) {
          setMeanAzi(aziName, sweepno);
        } else {
          if (sweepno >= nsweepsHR) {
            int swpNo = sweepno - (nsweepsHR);
            setMeanAzi(aziName, swpNo);
          } else {
            setMeanAzi(aziName + "_HI", sweepno);
          }
        }
      }

      private void setMeanAzi(String aziName, int swpNumber) {
        Array aziData;

        if (getType() != null) {
          try {
            Array data = ds.findVariable(aziName).read();
            int[] aziOrigin = new int[2];
            aziOrigin[0] = swpNumber;
            aziOrigin[1] = 0; // shape[1] - getRadialNumber();
            int[] aziShape = {1, getRadialNumber()};
            aziData = data.section(aziOrigin, aziShape);
            meanAzimuth = MAMath.sumDouble(aziData) / aziData.getSize();
          } catch (IOException e) {
            e.printStackTrace();
            meanAzimuth = 0.0;
          } catch (ucar.ma2.InvalidRangeException e) {
            e.printStackTrace();
          }

        } else
          meanAzimuth = 0.0;

      }

      public float getMeanAzimuth() {
        if (Double.isNaN(meanAzimuth))
          setMeanAzimuth();
        return (float) meanAzimuth;
      }

      public boolean isConic() {
        return true;
      }

      public float getElevation(int ray) throws IOException {
        String eleName = getRadialVarCoordinateName("elevation", sweepVar.getShortName());

        if (!isHighResolution(ds)) {
          return getEle(eleName, sweepno, ray);
        } else {
          if (sweepno >= nsweepsHR) {
            int swpNo = sweepno - (nsweepsHR);
            return getEle(eleName, swpNo, ray);
          } else {
            return getEle(eleName + "_HI", sweepno, ray);
          }
        }
      }

      public float getEle(String elevName, int swpNumber, int ray) throws IOException {
        float[] eleData = getEle(elevName, swpNumber);
        return eleData[ray];
      }

      public float[] getElevation() throws IOException {
        String eleName = getRadialVarCoordinateName("elevation", sweepVar.getShortName());

        if (!isHighResolution(ds)) {
          return getEle(eleName, sweepno);
        } else {
          if (sweepno >= nsweepsHR) {
            int swpNo = sweepno - (nsweepsHR);
            return getEle(eleName, swpNo);
          } else {
            return getEle(eleName + "_HI", sweepno);
          }
        }
      }

      public float[] getEle(String elevName, int swpNumber) throws IOException {
        try {
          Variable evar = ds.findVariable(elevName);
          Array eleData = evar.read();
          evar.setCachedData(eleData, false);
          int[] eleOrigin = new int[2];
          eleOrigin[0] = swpNumber;
          eleOrigin[1] = 0;
          int[] eleShape = {1, getRadialNumber()};
          eleData = eleData.section(eleOrigin, eleShape);
          return (float[]) eleData.get1DJavaArray(Float.TYPE);
        } catch (ucar.ma2.InvalidRangeException e) {
          throw new IOException(e);
        }
      }

      public float[] getAzimuth() throws IOException {
        String aziName = getRadialVarCoordinateName("azimuth", sweepVar.getShortName());

        if (!isHighResolution(ds)) {
          return getAzi(aziName, sweepno);
        } else {
          if (sweepno >= nsweepsHR) {
            int swpNo = sweepno - (nsweepsHR);
            return getAzi(aziName, swpNo);
          } else {
            return getAzi(aziName + "_HI", sweepno);
          }
        }
      }

      public float[] getAzi(String aziName, int swpNumber) throws IOException {
        try {
          Variable avar = ds.findVariable(aziName);
          Array aziData = avar.read();
          avar.setCachedData(aziData, false);
          int[] aziOrigin = new int[2];
          aziOrigin[0] = swpNumber;
          aziOrigin[1] = 0; // shape[1] - getRadialNumber();
          int[] aziShape = {1, getRadialNumber()};
          aziData = aziData.section(aziOrigin, aziShape);
          return (float[]) aziData.get1DJavaArray(Float.TYPE);
        } catch (ucar.ma2.InvalidRangeException e) {
          throw new IOException(e);
        }

      }

      public float getAzimuth(int ray) throws IOException {
        String aziName = getRadialVarCoordinateName("azimuth", sweepVar.getShortName());

        if (!isHighResolution(ds)) {
          return getAzi(aziName, sweepno, ray);
        } else {
          if (sweepno >= nsweepsHR) {
            int swpNo = sweepno - (nsweepsHR);
            return getAzi(aziName, swpNo, ray);
          } else {
            return getAzi(aziName + "_HI", sweepno, ray);
          }
        }
      }

      public float getAzi(String aziName, int swpNumber, int ray) throws IOException {
        float[] aziData = getAzi(aziName, swpNumber);
        return aziData[ray];
      }

      public float getRadialDistance(int gate) throws IOException {
        String disName = getRadialVarCoordinateName("distance", sweepVar.getShortName());

        if (!isHighResolution(ds)) {
          return getRadialDist(disName, gate);
        } else {
          if (sweepno >= nsweepsHR) {

            return getRadialDist(disName, gate);
          } else {
            return getRadialDist(disName + "_HI", gate);
          }
        }
      }

      public float getRadialDist(String dName, int gate) throws IOException {
        Variable dvar = ds.findVariable(dName);
        Array data = dvar.read();
        dvar.setCachedData(data, false);
        Index index = data.getIndex();
        return data.getFloat(index.set(gate));
      }

      public float getTime(int ray) throws IOException {
        String tName = getRadialVarCoordinateName("time", sweepVar.getShortName());

        if (!isHighResolution(ds)) {
          return getT(tName, sweepno, ray);
        } else {
          if (sweepno >= nsweepsHR) {
            int swpNo = sweepno - (nsweepsHR);
            return getT(tName, swpNo, ray);
          } else {
            return getT(tName + "_HI", sweepno, ray);
          }
        }
      }

      public String getRadialVarCoordinateName(String coord, String rVar) {
        String cName;
        if (rVar.startsWith("Reflectivity"))
          cName = coord + "R";
        else if (rVar.startsWith("DifferentialReflectivity"))
          cName = coord + "D";
        else if (rVar.startsWith("CorrelationCoefficient"))
          cName = coord + "C";
        else if (rVar.startsWith("DifferentialPhase"))
          cName = coord + "P";
        else
          cName = coord + "V";

        return cName;
      }


      public float getT(String tName, int swpNumber, int ray) throws IOException {
        Variable tvar = ds.findVariable(tName);
        Array timeData = tvar.read();
        tvar.setCachedData(timeData, false);
        Index timeIndex = timeData.getIndex();
        return timeData.getFloat(timeIndex.set(swpNumber, ray));
      }

      public float getBeamWidth() {
        return 0.95f; // degrees, info from Chris Burkhart
      }

      public float getNyquistFrequency() {
        return 0; // LOOK this may be radial specific
      }

      public float getRangeToFirstGate() {
        try {
          return getRadialDistance(0);
        } catch (IOException e) {
          e.printStackTrace();
          return 0.0f;
        }
      }

      public float getGateSize() {
        try {
          return getRadialDistance(1) - getRadialDistance(0);
        } catch (IOException e) {
          e.printStackTrace();
          return 0.0f;
        }
      }

      public boolean isGateSizeConstant() {
        return true;
      }

      public void clearSweepMemory() {

      }
    } // LevelII2Sweep class

  } // LevelII2Variable

} // LevelII2Dataset




© 2015 - 2025 Weber Informatics LLC | Privacy Policy