/* * 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.dt.*; import ucar.nc2.dataset.*; import ucar.nc2.constants.*; import ucar.nc2.ft.FeatureDataset; import ucar.nc2.time.CalendarDateUnit; import ucar.nc2.units.DateUnit; import ucar.nc2.VariableSimpleIF; import ucar.nc2.Variable; import ucar.nc2.Attribute; import ucar.nc2.Dimension; import ucar.ma2.*; import java.io.IOException; import java.util.*; import ucar.unidata.geoloc.EarthLocation; public class NsslRadialAdapter extends AbstractRadialAdapter { private NetcdfDataset ds; private boolean isVolume; private double latv, lonv, elev; ///////////////////////////////////////////////// public Object isMine(FeatureType wantFeatureType, NetcdfDataset ncd, Formatter errlog) { String format = ncd.getRootGroup().findAttributeString("format", null); if (format != null) { if (format.startsWith("nssl/netcdf")) return this; } Dimension az = ncd.findDimension("Azimuth"); Dimension gt = ncd.findDimension("Gate"); if ((null != az) && (null != gt)) { return this; } return null; } public FeatureDataset open(FeatureType ftype, NetcdfDataset ncd, Object analysis, ucar.nc2.util.CancelTask task, Formatter errlog) { return new NsslRadialAdapter(ncd); } public FeatureType getScientificDataType() { return FeatureType.RADIAL; } // needed for FeatureDatasetFactory public NsslRadialAdapter() {} /** * Constructor. * * @param ds must be from netcdf IOSP */ public NsslRadialAdapter(NetcdfDataset ds) { super(ds); this.ds = ds; desc = "Netcdf/NCML 2 radar dataset"; setEarthLocation(); try { setTimeUnits(); } catch (Exception e) { throw new RuntimeException(e); } setStartDate(); setEndDate(); setBoundingBox(); try { addCoordSystem(ds); } catch (IOException e) { e.printStackTrace(); } } private void addCoordSystem(NetcdfDataset ds) throws IOException { double ele = 0; Attribute attr = ds.findGlobalAttributeIgnoreCase("Elevation"); if (attr != null) ele = attr.getNumericValue().doubleValue(); // ncml agg add this sweep variable as agg dimension Variable sp = ds.findVariable("sweep"); if (sp == null) { // add Elevation ds.addDimension(null, new Dimension("Elevation", 1)); String lName = "elevation angle in degres: 0 = parallel to pedestal base, 90 = perpendicular"; CoordinateAxis v = new CoordinateAxis1D(ds, null, "Elevation", DataType.DOUBLE, "Elevation", "degrees", lName); ds.setValues(v, 1, ele, 0); v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialElevation.toString())); ds.addVariable(null, v); } else { Array spdata = sp.read(); float[] spd = (float[]) spdata.get1DJavaArray(float.class); int spsize = spd.length; // add Elevation ds.addDimension(null, new Dimension("Elevation", spsize)); String lName = "elevation angle in degres: 0 = parallel to pedestal base, 90 = perpendicular"; CoordinateAxis v = new CoordinateAxis1D(ds, null, "Elevation", DataType.DOUBLE, "Elevation", "degrees", lName); v.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialElevation.toString())); ds.addVariable(null, v); } ds.addAttribute(null, new Attribute("IsRadial", 1)); attr = ds.findGlobalAttributeIgnoreCase("vcp-value"); String vcp; if (attr == null) vcp = "11"; else vcp = attr.getStringValue(); ds.addAttribute(null, new Attribute("VolumeCoveragePatternName", vcp)); ds.finish(); } public ucar.unidata.geoloc.EarthLocation getCommonOrigin() { return origin; } public String getRadarID() { Attribute ga = ds.findGlobalAttribute("radarName-value"); if (ga != null) return ga.getStringValue(); else return "XXXX"; } public boolean isStationary() { return true; } public String getRadarName() { return ds.findGlobalAttribute("ProductStationName").getStringValue(); } public String getDataFormat() { return "NetCDF Level II"; } public void setIsVolume(NetcdfDataset nds) { String format = nds.getRootGroup().findAttributeString("volume", null); if (format == null) { isVolume = false; return; } isVolume = format.equals("true"); } public boolean isVolume() { return isVolume; } protected void setEarthLocation() { Attribute ga = ds.findGlobalAttribute("Latitude"); if (ga != null) latv = ga.getNumericValue().doubleValue(); else latv = 0.0; ga = ds.findGlobalAttribute("Longitude"); if (ga != null) lonv = ga.getNumericValue().doubleValue(); else lonv = 0.0; ga = ds.findGlobalAttribute("Height"); if (ga != null) elev = ga.getNumericValue().doubleValue(); else elev = 0.0; origin = EarthLocation.create(latv, lonv, elev); } 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 = DateUnit.getStandardOrISO(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 = DateUnit.getStandardOrISO(end_datetime); else parseInfo.append("*** end_datetime not Found\n"); } protected void addRadialVariable(NetcdfDataset nds, Variable var) { RadialVariable rsvar = null; int rnk = var.getRank(); setIsVolume(nds); if (isVolume && rnk == 3) { rsvar = makeRadialVariable(nds, var); } else if (!isVolume && rnk == 2) { rsvar = makeRadialVariable(nds, var); } if (rsvar != null) dataVariables.add(rsvar); } protected RadialVariable makeRadialVariable(NetcdfDataset nds, Variable v0) { return new Netcdf2Variable(nds, v0); } public void clearDatasetMemory() { for (VariableSimpleIF rvar : getDataVariables()) { RadialVariable radVar = (RadialVariable) rvar; radVar.clearVariableMemory(); } } public String getInfo() { String sbuff = "Netcdfs2Dataset\n" + super.getDetailInfo() + "\n\n" + parseInfo; return sbuff; } private class Netcdf2Variable extends MyRadialVariableAdapter implements RadialDatasetSweep.RadialVariable { ArrayList<Netcdf2Sweep> sweeps; int nsweeps; private Netcdf2Variable(NetcdfDataset nds, Variable v0) { super(v0.getShortName(), v0); sweeps = new ArrayList<>(); nsweeps = 0; int[] shape = v0.getShape(); int count = v0.getRank() - 1; int ngates = shape[count]; count--; int nrays = shape[count]; count--; if (shape.length == 3) nsweeps = shape[count]; else nsweeps = 1; for (int i = 0; i < nsweeps; i++) sweeps.add(new Netcdf2Sweep(v0, i, nrays, ngates)); } public String toString() { return name; } public float[] readAllData() throws IOException { Array allData; Sweep spn = sweeps.get(0); Variable v = spn.getsweepVar(); try { allData = v.read(); } catch (IOException e) { throw new IOException(e.getMessage()); } return (float[]) allData.get1DJavaArray(float.class); } public int getNumSweeps() { return nsweeps; } public Sweep getSweep(int sweepNo) { return sweeps.get(sweepNo); } public void clearVariableMemory() { // doing nothing } ////////////////////////////////////////////////////////////////////// private class Netcdf2Sweep implements RadialDatasetSweep.Sweep { double meanElevation = Double.NaN; double meanAzimuth = Double.NaN; int sweepno, nrays, ngates; Variable sweepVar; Netcdf2Sweep(Variable v, int sweepno, int rays, int gates) { this.sweepno = sweepno; this.nrays = rays; this.ngates = gates; this.sweepVar = v; } public Variable getsweepVar() { return sweepVar; } public float[] readData() throws java.io.IOException { Array allData; int[] shape = sweepVar.getShape(); int[] origind = new int[sweepVar.getRank()]; if (isVolume) { origind[0] = sweepno; origind[1] = 0; shape[0] = 1; } try { allData = sweepVar.read(origind, shape); } catch (InvalidRangeException e) { throw new IOException(e.getMessage()); } int nradials = shape[0]; int ngates = shape[1]; IndexIterator dataIter = allData.getIndexIterator(); for (int j = 0; j < nradials; j++) { for (int i = 0; i < ngates; i++) { float tp = dataIter.getFloatNext(); if (tp == -32768.0f || tp == -99900.0f) { dataIter.setFloatCurrent(Float.NaN); } } } return (float[]) allData.get1DJavaArray(float.class); } /* read 1d data ngates */ public float[] readData(int ray) throws java.io.IOException { Array rayData; int[] shape = sweepVar.getShape(); int[] origind = new int[sweepVar.getRank()]; if (isVolume) { origind[0] = sweepno; origind[1] = ray; shape[0] = 1; shape[1] = 1; } else { shape[0] = 1; origind[0] = ray; } try { rayData = sweepVar.read(origind, shape); } catch (ucar.ma2.InvalidRangeException e) { throw new IOException(e.getMessage()); } int ngates = shape[1]; IndexIterator dataIter = rayData.getIndexIterator(); for (int i = 0; i < ngates; i++) { float tp = dataIter.getFloatNext(); if (tp == -32768.0f || tp == -99900.0f) { dataIter.setFloatCurrent(Float.NaN); } } return (float[]) rayData.get1DJavaArray(float.class); } private void setMeanElevation() { if (isVolume) { try { Variable sp = ds.findVariable("sweep"); Array spData = sp.read(); float[] spArray = (float[]) spData.get1DJavaArray(float.class); meanElevation = spArray[sweepno]; } catch (IOException e) { e.printStackTrace(); meanElevation = 0.0; } } else { Attribute data = ds.findGlobalAttribute("Elevation"); meanElevation = data.getNumericValue().doubleValue(); } } 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; } private void setMeanAzimuth() { meanAzimuth = 0.0; } public float getMeanAzimuth() { if (Double.isNaN(meanAzimuth)) setMeanAzimuth(); return (float) meanAzimuth; } public boolean isConic() { return true; } public float getElevation(int ray) { return (float) meanElevation; } public float[] getElevation() { float[] dataValue = new float[nrays]; for (int i = 0; i < nrays; i++) { dataValue[i] = (float) meanElevation; } return dataValue; } public float[] getAzimuth() throws IOException { Array aziData = ds.findVariable("Azimuth").read(); return (float[]) aziData.get1DJavaArray(float.class); } public float getAzimuth(int ray) throws IOException { String aziName = "Azimuth"; try { Array aziData = ds.findVariable(aziName).read(); if (isVolume) { int[] aziOrigin = new int[2]; aziOrigin[0] = sweepno; aziOrigin[1] = 0; int[] aziShape = {1, getRadialNumber()}; aziData = aziData.section(aziOrigin, aziShape); } Index index = aziData.getIndex(); return aziData.getFloat(index.set(ray)); } catch (ucar.ma2.InvalidRangeException e) { throw new IOException(e); } } public float getRadialDistance(int gate) throws IOException { float gateStart = getRangeToFirstGate(); Variable gateSize = ds.findVariable("GateWidth"); float[] data = (float[]) gateSize.read().get1DJavaArray(float.class); float dist = gateStart + gate * data[0]; return dist; } public float getTime(int ray) { return startDate.getTime(); } 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() { Attribute firstGate = ds.findGlobalAttributeIgnoreCase("RangeToFirstGate"); double gateStart = firstGate.getNumericValue().doubleValue(); return (float) gateStart; } 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() { } } // Netcdf2Sweep class } // Netcdf2Variable }