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

ucar.nc2.iosp.uf.UFiosp 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.iosp.uf;

import ucar.nc2.constants.*;
import ucar.nc2.iosp.AbstractIOServiceProvider;

import ucar.nc2.Variable;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Dimension;
import ucar.nc2.Attribute;
import ucar.nc2.units.DateFormatter;
import ucar.ma2.*;

import java.io.IOException;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: yuanho
 * Date: Sep 25, 2008
 * Time: 10:23:36 AM
 * To change this template use File | Settings | File Templates.
 */
public class UFiosp extends AbstractIOServiceProvider {
  static private final int MISSING_INT = -9999;
  static private final float MISSING_FLOAT = Float.NaN;
  protected UFheader headerParser;

  public boolean isValidFile(ucar.unidata.io.RandomAccessFile raf) {
    UFheader localHeader = new UFheader();
    return (localHeader.isValidFile(raf));
  }

  public String getFileTypeId() {
    return "UniversalRadarFormat";
  }

  public String getFileTypeDescription() {
    return "Universal Radar Format";
  }

  public void open(ucar.unidata.io.RandomAccessFile raf, ucar.nc2.NetcdfFile ncfile,
                   ucar.nc2.util.CancelTask cancelTask) throws IOException {
    super.open(raf, ncfile, cancelTask);

    headerParser = new UFheader();
    headerParser.read(this.raf);
    //Map variables = headerParser.variableGroup;

    for (Map.Entry>> entry : headerParser.variableGroup.entrySet()) {
      String key = entry.getKey();
      List> groups = entry.getValue();
      List rays = groups.get(0);
      Ray ray0 = rays.get(0);
      makeVariable(ncfile, ray0.getDatatypeName(key), ray0.getDatatypeName(key), key, groups);
    }


    ncfile.addAttribute(null, new Attribute(CDM.CONVENTIONS, _Coordinate.Convention));
    ncfile.addAttribute(null, new Attribute("format", headerParser.getDataFormat()));
    ncfile.addAttribute(null, new Attribute("cdm_data_type", FeatureType.RADIAL.toString()));
    ncfile.addAttribute(null, new Attribute("instrument_name", headerParser.getRadarName()));
    ncfile.addAttribute(null, new Attribute("site_name", headerParser.getSiteName()));
    //Date d = Cinrad2Record.getDate(volScan.getTitleJulianDays(), volScan.getTitleMsecs());
    //ncfile.addAttribute(null, new Attribute("base_date", formatter.toDateOnlyString(d)));
    ncfile.addAttribute(null, new Attribute("StationLatitude", (double) headerParser.getStationLatitude()));
    ncfile.addAttribute(null, new Attribute("StationLongitude", (double) headerParser.getStationLongitude()));
    ncfile.addAttribute(null, new Attribute("StationElevationInMeters", (double) headerParser.getStationElevation()));
    ncfile.addAttribute(null, new Attribute("time_coverage_start", formatter.toDateTimeStringISO(headerParser.getStartDate())));
    //.toDateTimeStringISO(d)));
    ncfile.addAttribute(null, new Attribute("time_coverage_end", formatter.toDateTimeStringISO(headerParser.getEndDate())));
    double latRadiusDegrees = Math.toDegrees(radarRadius / ucar.unidata.geoloc.Earth.getRadius());
    ncfile.addAttribute(null, new Attribute("geospatial_lat_min", headerParser.getStationLatitude() - latRadiusDegrees));
    ncfile.addAttribute(null, new Attribute("geospatial_lat_max", headerParser.getStationLatitude() + latRadiusDegrees));
    double cosLat = Math.cos(Math.toRadians(headerParser.getStationLatitude()));
    double lonRadiusDegrees = Math.toDegrees(radarRadius / cosLat / ucar.unidata.geoloc.Earth.getRadius());
    ncfile.addAttribute(null, new Attribute("geospatial_lon_min", headerParser.getStationLongitude() - lonRadiusDegrees));
    ncfile.addAttribute(null, new Attribute("geospatial_lon_max", headerParser.getStationLongitude() + lonRadiusDegrees));
    ncfile.addAttribute(null, new Attribute(CDM.HISTORY, "Direct read of UF Radar by CDM (version 4.5)"));
    ncfile.addAttribute(null, new Attribute("DataType", "Radial"));

    ncfile.addAttribute(null, new Attribute("Title", "Radar Data from station" +
            " " + headerParser.getRadarName() + " from " +
            formatter.toDateTimeStringISO(headerParser.getStartDate()) + " to " +
            formatter.toDateTimeStringISO(headerParser.getEndDate())));

    ncfile.addAttribute(null, new Attribute("SweepMode", headerParser.getSweepMode()));

    // ncfile.addAttribute(null, new Attribute("VolumeCoveragePattern", new Integer(headerParser.getVCP())));
    // ncfile.addAttribute(null, new Attribute("HorizonatalBeamWidthInDegrees", new Double(headerParser.getHorizontalBeamWidth(abbrev))));

    ncfile.finish();
  }


  private DateFormatter formatter = new DateFormatter();
  private double radarRadius = 100000.0;

  public Variable makeVariable(NetcdfFile ncfile, 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 = groups.get(0);
    Ray firstRay = firstGroup.get(0);
    int ngates = firstRay.getGateCount(abbrev);

    String scanDimName = "scan" + abbrev;
    String gateDimName = "gate" + abbrev;
    String radialDimName = "radial" + abbrev;
    Dimension scanDim = new Dimension(scanDimName, nscans);
    Dimension gateDim = new Dimension(gateDimName, ngates);
    Dimension radialDim = new Dimension(radialDimName, headerParser.getMaxRadials(), true);
    ncfile.addDimension(null, scanDim);
    ncfile.addDimension(null, gateDim);
    ncfile.addDimension(null, radialDim);

    List dims = new ArrayList<>();
    dims.add(scanDim);
    dims.add(radialDim);
    dims.add(gateDim);

    Variable v = new Variable(ncfile, null, null, shortName + abbrev);
    v.setDataType(DataType.SHORT);
    v.setDimensions(dims);
    ncfile.addVariable(null, v);

    v.addAttribute(new Attribute(CDM.UNITS, firstRay.getDatatypeUnits(abbrev)));
    v.addAttribute(new Attribute(CDM.LONG_NAME, longName));
    v.addAttribute(new Attribute("abbrev", abbrev));
    v.addAttribute(new Attribute(CDM.MISSING_VALUE, firstRay.getMissingData()));
    v.addAttribute(new Attribute("signal_below_threshold", firstRay.getDatatypeRangeFoldingThreshhold(abbrev)));
    v.addAttribute(new Attribute(CDM.SCALE_FACTOR, firstRay.getDatatypeScaleFactor(abbrev)));
    v.addAttribute(new Attribute(CDM.ADD_OFFSET, firstRay.getDatatypeAddOffset(abbrev)));
    // v.addAttribute( new Attribute(CDM.UNSIGNED, "false"));

    v.addAttribute(new Attribute("range_folding_threshold", firstRay.getDatatypeRangeFoldingThreshhold(abbrev)));

    List 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 = Level2Record.getDate( julianDays, 0);
    Date d = firstRay.getDate();
    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, firstRay.getMissingData()));
    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 degrees: 0 = parallel to pedestal base, 90 = perpendicular"));
    elevVar.addAttribute(new Attribute(CDM.MISSING_VALUE, firstRay.getMissingData()));
    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, firstRay.getMissingData()));
    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) firstRay.getGateStart(abbrev), (double) firstRay.getGateSize(abbrev));
    gateVar.setCachedData(data, false);
    ncfile.addVariable(null, gateVar);
    //      radarRadius = firstRay.getGateStart(datatype) + ngates * firstRay.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.getShortName());
    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.getShortName());
    ngateVar.addAttribute(new Attribute(CDM.LONG_NAME, "number of valid gates in this scan"));
    ncfile.addVariable(null, ngateVar);

    makeCoordinateDataWithMissing(abbrev, 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 ray map
    int nradials = radialDim.getLength();
    Ray[][] map = new Ray[nscans][nradials];
    for (int i = 0; i < groups.size(); i++) {
      Ray[] mapScan = map[i];
      List group = groups.get(i);
      int radial = 0;
      for (Ray r : group) {
        mapScan[radial] = r;
        radial++;
      }
    }

    Vgroup vg = new Vgroup(abbrev, map);
    v.setSPobject(vg);

    return v;
  }

  private void makeCoordinateDataWithMissing(String abbrev, Variable time, Variable elev, Variable azi, Variable nradialsVar,
                                             Variable ngatesVar, List> groups) {

    Array timeData = Array.factory(time.getDataType(), time.getShape());
    Index timeIndex = timeData.getIndex();

    Array elevData = Array.factory(elev.getDataType(), elev.getShape());
    Index elevIndex = elevData.getIndex();

    Array aziData = Array.factory(azi.getDataType(), azi.getShape());
    Index aziIndex = aziData.getIndex();

    Array nradialsData = Array.factory(nradialsVar.getDataType(), nradialsVar.getShape());
    IndexIterator nradialsIter = nradialsData.getIndexIterator();

    Array ngatesData = Array.factory(ngatesVar.getDataType(), ngatesVar.getShape());
    IndexIterator ngatesIter = ngatesData.getIndexIterator();

    // first fill with missing data
    IndexIterator ii = timeData.getIndexIterator();
    while (ii.hasNext())
      ii.setIntNext(MISSING_INT);

    ii = elevData.getIndexIterator();
    while (ii.hasNext())
      ii.setFloatNext(MISSING_FLOAT);

    ii = aziData.getIndexIterator();
    while (ii.hasNext())
      ii.setFloatNext(MISSING_FLOAT);

    int nscans = groups.size();
    try {
      for (int scan = 0; scan < nscans; scan++) {
        List scanGroup = groups.get(scan);
        int nradials = scanGroup.size();

        int radial = 0;
        boolean needFirst = true;
        for (Ray r : scanGroup) {
          if (needFirst)
          {
              ngatesIter.setIntNext(r.getGateCount(abbrev));
              needFirst = false;
          }

          // int radial = r.uf_header2.rayNumber ;
          // if(scan == 0) System.out.println("AZI " + r.getAzimuth());
          timeData.setLong(timeIndex.set(scan, radial), r.data_msecs);
          elevData.setFloat(elevIndex.set(scan, radial), r.getElevation());
          aziData.setFloat(aziIndex.set(scan, radial), r.getAzimuth());
          radial++;
        }

        nradialsIter.setIntNext(nradials);
      }
    } catch (java.lang.ArrayIndexOutOfBoundsException ae) {

    }
    time.setCachedData(timeData, false);
    elev.setCachedData(elevData, false);
    azi.setCachedData(aziData, false);
    nradialsVar.setCachedData(nradialsData, false);
    ngatesVar.setCachedData(ngatesData, false);
  }

  private static class Vgroup {
    Ray[][] map;
    String abbrev;

    Vgroup(String abbrev, Ray[][] map) {
      this.abbrev = abbrev;
      this.map = map;
    }
  }

  public Array readData(Variable v2, Section section) throws IOException, InvalidRangeException {
    Vgroup vgroup = (Vgroup) v2.getSPobject();

    Range scanRange = section.getRange(0);
    Range radialRange = section.getRange(1);
    Range gateRange = section.getRange(2);

    Array data = Array.factory(v2.getDataType(), section.getShape());
    IndexIterator ii = data.getIndexIterator();

    for (int scanIdx : scanRange) {
      Ray[] mapScan = vgroup.map[scanIdx];
      readOneScan(mapScan, radialRange, gateRange, vgroup.abbrev, ii);
    }

    return data;
  }

  private void readOneScan(Ray[] mapScan, Range radialRange, Range gateRange, String abbrev, IndexIterator ii) throws IOException {
    for (int radialIdx : radialRange) {
      Ray r = mapScan[radialIdx];
      readOneRadial(r, abbrev, gateRange, ii);
    }
  }

  private void readOneRadial(Ray r, String abbrev, Range gateRange, IndexIterator ii) throws IOException {
    if (r == null) {
      for (int i = 0; i < gateRange.length(); i++)
        ii.setShortNext(headerParser.getMissingData());
      return;
    }
    r.readData(raf, abbrev, gateRange, ii);
  }



}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy