public Variable makeVariable( NetcdfFile ncfile, int datatype, String shortName, String longName, String abbrev, List groups) throws IOException { int nscans = groups.size(); if (nscans == 0) { throw new IllegalStateException("No data for " + shortName); } // get representative record List firstGroup = (List) groups.get(0); Cinrad2Record firstRecord = (Cinrad2Record) firstGroup.get(0); int ngates = firstRecord.getGateCount(datatype); String scanDimName = "scan" + abbrev; String gateDimName = "gate" + abbrev; Dimension scanDim = new Dimension(scanDimName, nscans); Dimension gateDim = new Dimension(gateDimName, ngates); ncfile.addDimension(null, scanDim); ncfile.addDimension(null, gateDim); ArrayList dims = new ArrayList(); dims.add(scanDim); dims.add(radialDim); dims.add(gateDim); Variable v = new Variable(ncfile, null, null, shortName); v.setDataType(DataType.BYTE); v.setDimensions(dims); ncfile.addVariable(null, v); v.addAttribute(new Attribute(CDM.UNITS, Cinrad2Record.getDatatypeUnits(datatype))); v.addAttribute(new Attribute(CDM.LONG_NAME, longName)); byte[] b = new byte[2]; b[0] = Cinrad2Record.MISSING_DATA; b[1] = Cinrad2Record.BELOW_THRESHOLD; Array missingArray = Array.factory(DataType.BYTE.getPrimitiveClassType(), new int[] {2}, b); v.addAttribute(new Attribute(CDM.MISSING_VALUE, missingArray)); v.addAttribute( new Attribute("signal_below_threshold", new Byte(Cinrad2Record.BELOW_THRESHOLD))); v.addAttribute( new Attribute(CDM.SCALE_FACTOR, new Float(Cinrad2Record.getDatatypeScaleFactor(datatype)))); v.addAttribute( new Attribute(CDM.ADD_OFFSET, new Float(Cinrad2Record.getDatatypeAddOffset(datatype)))); v.addAttribute(new Attribute(CDM.UNSIGNED, "true")); ArrayList dim2 = new ArrayList(); dim2.add(scanDim); dim2.add(radialDim); // add time coordinate variable String timeCoordName = "time" + abbrev; Variable timeVar = new Variable(ncfile, null, null, timeCoordName); timeVar.setDataType(DataType.INT); timeVar.setDimensions(dim2); ncfile.addVariable(null, timeVar); // int julianDays = volScan.getTitleJulianDays(); // Date d = Cinrad2Record.getDate( julianDays, 0); // Date d = Cinrad2Record.getDate(volScan.getTitleJulianDays(), volScan.getTitleMsecs()); Date d = volScan.getStartDate(); String units = "msecs since " + formatter.toDateTimeStringISO(d); timeVar.addAttribute(new Attribute(CDM.LONG_NAME, "time since base date")); timeVar.addAttribute(new Attribute(CDM.UNITS, units)); timeVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Integer(MISSING_INT))); timeVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.Time.toString())); // add elevation coordinate variable String elevCoordName = "elevation" + abbrev; Variable elevVar = new Variable(ncfile, null, null, elevCoordName); elevVar.setDataType(DataType.FLOAT); elevVar.setDimensions(dim2); ncfile.addVariable(null, elevVar); elevVar.addAttribute(new Attribute(CDM.UNITS, "degrees")); elevVar.addAttribute( new Attribute( CDM.LONG_NAME, "elevation angle in degres: 0 = parallel to pedestal base, 90 = perpendicular")); elevVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Float(MISSING_FLOAT))); elevVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialElevation.toString())); // add azimuth coordinate variable String aziCoordName = "azimuth" + abbrev; Variable aziVar = new Variable(ncfile, null, null, aziCoordName); aziVar.setDataType(DataType.FLOAT); aziVar.setDimensions(dim2); ncfile.addVariable(null, aziVar); aziVar.addAttribute(new Attribute(CDM.UNITS, "degrees")); aziVar.addAttribute( new Attribute(CDM.LONG_NAME, "azimuth angle in degrees: 0 = true north, 90 = east")); aziVar.addAttribute(new Attribute(CDM.MISSING_VALUE, new Float(MISSING_FLOAT))); aziVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialAzimuth.toString())); // add gate coordinate variable String gateCoordName = "distance" + abbrev; Variable gateVar = new Variable(ncfile, null, null, gateCoordName); gateVar.setDataType(DataType.FLOAT); gateVar.setDimensions(gateDimName); Array data = Array.makeArray( DataType.FLOAT, ngates, (double) firstRecord.getGateStart(datatype), (double) firstRecord.getGateSize(datatype)); gateVar.setCachedData(data, false); ncfile.addVariable(null, gateVar); radarRadius = firstRecord.getGateStart(datatype) + ngates * firstRecord.getGateSize(datatype); gateVar.addAttribute(new Attribute(CDM.UNITS, "m")); gateVar.addAttribute(new Attribute(CDM.LONG_NAME, "radial distance to start of gate")); gateVar.addAttribute(new Attribute(_Coordinate.AxisType, AxisType.RadialDistance.toString())); // add number of radials variable String nradialsName = "numRadials" + abbrev; Variable nradialsVar = new Variable(ncfile, null, null, nradialsName); nradialsVar.setDataType(DataType.INT); nradialsVar.setDimensions(scanDim.getName()); nradialsVar.addAttribute(new Attribute(CDM.LONG_NAME, "number of valid radials in this scan")); ncfile.addVariable(null, nradialsVar); // add number of gates variable String ngateName = "numGates" + abbrev; Variable ngateVar = new Variable(ncfile, null, null, ngateName); ngateVar.setDataType(DataType.INT); ngateVar.setDimensions(scanDim.getName()); ngateVar.addAttribute(new Attribute(CDM.LONG_NAME, "number of valid gates in this scan")); ncfile.addVariable(null, ngateVar); makeCoordinateDataWithMissing( datatype, timeVar, elevVar, aziVar, nradialsVar, ngateVar, groups); // back to the data variable String coordinates = timeCoordName + " " + elevCoordName + " " + aziCoordName + " " + gateCoordName; v.addAttribute(new Attribute(_Coordinate.Axes, coordinates)); // make the record map int nradials = radialDim.getLength(); Cinrad2Record[][] map = new Cinrad2Record[nscans][nradials]; for (int i = 0; i < groups.size(); i++) { Cinrad2Record[] mapScan = map[i]; List group = (List) groups.get(i); for (int j = 0; j < group.size(); j++) { Cinrad2Record r = (Cinrad2Record) group.get(j); int radial = r.radial_num - 1; mapScan[radial] = r; } } Vgroup vg = new Vgroup(datatype, map); v.setSPobject(vg); return v; }
public void open(RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask) throws IOException { NexradStationDB.init(); volScan = new Cinrad2VolumeScan(raf, cancelTask); if (volScan.hasDifferentDopplarResolutions()) throw new IllegalStateException("volScan.hasDifferentDopplarResolutions"); radialDim = new Dimension("radial", volScan.getMaxRadials()); ncfile.addDimension(null, radialDim); makeVariable( ncfile, Cinrad2Record.REFLECTIVITY, "Reflectivity", "Reflectivity", "R", volScan.getReflectivityGroups()); int velocity_type = (volScan.getDopplarResolution() == Cinrad2Record.DOPPLER_RESOLUTION_HIGH_CODE) ? Cinrad2Record.VELOCITY_HI : Cinrad2Record.VELOCITY_LOW; Variable v = makeVariable( ncfile, velocity_type, "RadialVelocity", "Radial Velocity", "V", volScan.getVelocityGroups()); makeVariableNoCoords( ncfile, Cinrad2Record.SPECTRUM_WIDTH, "SpectrumWidth", "Spectrum Width", v); if (volScan.getStationId() != null) { ncfile.addAttribute(null, new Attribute("Station", volScan.getStationId())); ncfile.addAttribute(null, new Attribute("StationName", volScan.getStationName())); ncfile.addAttribute( null, new Attribute("StationLatitude", new Double(volScan.getStationLatitude()))); ncfile.addAttribute( null, new Attribute("StationLongitude", new Double(volScan.getStationLongitude()))); ncfile.addAttribute( null, new Attribute("StationElevationInMeters", new Double(volScan.getStationElevation()))); double latRadiusDegrees = Math.toDegrees(radarRadius / ucar.unidata.geoloc.Earth.getRadius()); ncfile.addAttribute( null, new Attribute( "geospatial_lat_min", new Double(volScan.getStationLatitude() - latRadiusDegrees))); ncfile.addAttribute( null, new Attribute( "geospatial_lat_max", new Double(volScan.getStationLatitude() + latRadiusDegrees))); double cosLat = Math.cos(Math.toRadians(volScan.getStationLatitude())); double lonRadiusDegrees = Math.toDegrees(radarRadius / cosLat / ucar.unidata.geoloc.Earth.getRadius()); ncfile.addAttribute( null, new Attribute( "geospatial_lon_min", new Double(volScan.getStationLongitude() - lonRadiusDegrees))); ncfile.addAttribute( null, new Attribute( "geospatial_lon_max", new Double(volScan.getStationLongitude() + lonRadiusDegrees))); // add a radial coordinate transform (experimental) Variable ct = new Variable(ncfile, null, null, "radialCoordinateTransform"); ct.setDataType(DataType.CHAR); ct.setDimensions(""); // scalar ct.addAttribute(new Attribute("transform_name", "Radial")); ct.addAttribute(new Attribute("center_latitude", new Double(volScan.getStationLatitude()))); ct.addAttribute(new Attribute("center_longitude", new Double(volScan.getStationLongitude()))); ct.addAttribute(new Attribute("center_elevation", new Double(volScan.getStationElevation()))); ct.addAttribute(new Attribute(_Coordinate.TransformType, "Radial")); ct.addAttribute( new Attribute(_Coordinate.AxisTypes, "RadialElevation RadialAzimuth RadialDistance")); Array data = Array.factory(DataType.CHAR.getPrimitiveClassType(), new int[0], new char[] {' '}); ct.setCachedData(data, true); ncfile.addVariable(null, ct); } DateFormatter formatter = new DateFormatter(); ncfile.addAttribute(null, new Attribute(CDM.CONVENTIONS, _Coordinate.Convention)); ncfile.addAttribute(null, new Attribute("format", volScan.getDataFormat())); ncfile.addAttribute(null, new Attribute(CF.FEATURE_TYPE, FeatureType.RADIAL.toString())); // Date d = Cinrad2Record.getDate(volScan.getTitleJulianDays(), volScan.getTitleMsecs()); // ncfile.addAttribute(null, new Attribute("base_date", formatter.toDateOnlyString(d))); ncfile.addAttribute( null, new Attribute( "time_coverage_start", formatter.toDateTimeStringISO(volScan.getStartDate()))); ; // .toDateTimeStringISO(d))); ncfile.addAttribute( null, new Attribute("time_coverage_end", formatter.toDateTimeStringISO(volScan.getEndDate()))); ncfile.addAttribute( null, new Attribute(CDM.HISTORY, "Direct read of Nexrad Level 2 file into NetCDF-Java 2.2 API")); ncfile.addAttribute(null, new Attribute("DataType", "Radial")); ncfile.addAttribute( null, new Attribute( "Title", "Nexrad Level 2 Station " + volScan.getStationId() + " from " + formatter.toDateTimeStringISO(volScan.getStartDate()) + " to " + formatter.toDateTimeStringISO(volScan.getEndDate()))); ncfile.addAttribute( null, new Attribute( "Summary", "Weather Surveillance Radar-1988 Doppler (WSR-88D) " + "Level II data are the three meteorological base data quantities: reflectivity, mean radial velocity, and " + "spectrum width.")); ncfile.addAttribute( null, new Attribute( "keywords", "WSR-88D; NEXRAD; Radar Level II; reflectivity; mean radial velocity; spectrum width")); ncfile.addAttribute( null, new Attribute( "VolumeCoveragePatternName", Cinrad2Record.getVolumeCoveragePatternName(volScan.getVCP()))); ncfile.addAttribute( null, new Attribute("VolumeCoveragePattern", new Integer(volScan.getVCP()))); ncfile.addAttribute( null, new Attribute( "HorizonatalBeamWidthInDegrees", new Double(Cinrad2Record.HORIZONTAL_BEAM_WIDTH))); ncfile.finish(); }