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

ucar.nc2.iosp.uf.Ray Maven / Gradle / Ivy

Go to download

The NetCDF-Java Library is a Java interface to NetCDF files, as well as to many other types of scientific data formats.

The newest version!
/*
 * Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
 *
 * Portions of this software were developed by the Unidata Program at the
 * University Corporation for Atmospheric Research.
 *
 * Access and use of this software shall impose the following obligations
 * and understandings on the user. The user is granted the right, without
 * any fee or cost, to use, copy, modify, alter, enhance and distribute
 * this software, and any derivative works thereof, and its supporting
 * documentation for any purpose whatsoever, provided that this entire
 * notice appears in all copies of the software, derivative works and
 * supporting documentation.  Further, UCAR requests that the user credit
 * UCAR/Unidata in any publications that result from the use of this
 * software or in any product that includes this software. The names UCAR
 * and/or Unidata, however, may not be used in any advertising or publicity
 * to endorse or promote any products or commercial entity unless specific
 * written permission is obtained from UCAR/Unidata. The user also
 * understands that UCAR/Unidata is not obligated to provide the user with
 * any support, consulting, training or assistance of any kind with regard
 * to the use, operation and performance of this software nor to provide
 * the user with any updates, revisions, new versions or "bug fixes."
 *
 * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
 */
package ucar.nc2.iosp.uf;

import ucar.nc2.constants.CDM;
import ucar.unidata.io.RandomAccessFile;
import ucar.ma2.Range;
import ucar.ma2.IndexIterator;

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

public class Ray {
    int raySize;
    long rayOffset;
    static final int UF_MANDATORY_HEADER2_LEN = 90;
    static final int UF_FIELD_HEADER2_LEN = 50;
    boolean debug = false;

     /**   moment identifier */
    long data_msecs = 0;

    UF_mandatory_header2 uf_header2;
    UF_optional_header uf_opt_header;
    short      numberOfFields;   // in this ray
    short      numberOfRecords;  // in this ray
    short      numberOfFieldsInRecord;   // in this record

    Map field_header_map;  // key = 2 byte "data type"

    public Ray( ByteBuffer bos, int raySize, long rayOffset) {
        this.raySize = raySize;
        this.rayOffset = rayOffset;
        field_header_map = new HashMap<>();
        bos.position(0);

        byte[] data = new byte[UF_MANDATORY_HEADER2_LEN];
        bos.get(data);

        uf_header2 = new  UF_mandatory_header2(data);

        if(uf_header2.offset2StartOfOptionalHeader > 0 &&
                (uf_header2.dataHeaderPosition != uf_header2.offset2StartOfOptionalHeader)){
            data = new byte[28];
            bos.get(data);
            uf_opt_header = new UF_optional_header(data);
        }
        int position = uf_header2.dataHeaderPosition*2 -2;
        bos.position(position);
        data_msecs = setDateMesc();
        byte [] b2 = new byte[2];
        bos.get(b2);
        numberOfFields = getShort(b2, 0);
        bos.get(b2);
        numberOfRecords = getShort(b2, 0);
        bos.get(b2);
        numberOfFieldsInRecord = getShort(b2, 0);
        data = new byte[UF_FIELD_HEADER2_LEN];
        for(int i = 0; i < numberOfFields; i++){
            bos.get(b2);
            //int type = getShort(b2, 0);
            String type = new String(b2, CDM.utf8Charset);
            bos.get(b2);
            int offs = getShort(b2, 0);
            int position0 = bos.position();
            bos.position(offs*2 - 2);
            bos.get(data);
            UF_field_header2 field_header = new UF_field_header2(data);
            bos.position(position0);
            field_header_map.put(type, field_header);
        }
    }

    public int getRaySize(){
        return raySize;
    }

    public int getGateCount(String abbrev) {
        UF_field_header2 header = field_header_map.get(abbrev);
        return header.binCount;
    }

    public String getDatatypeName(String abbrev) {
        if( abbrev.equals("ZN") || abbrev.equals("ZS"))
          return "Reflectivity";
        else if (abbrev.equals("ZF") || abbrev.equals("ZX") || abbrev.equals("DR"))
          return "Reflectivity";
        else if(abbrev.equals("VR") || abbrev.equals("DN") || abbrev.equals("DS") || abbrev.equals("DF") ||abbrev.equals("DX") )
          return "RadialVelocity";
        else if(abbrev.equals("VN") || abbrev.equals("VF") )
          return "CorrectedRadialVelocity";
        else if(abbrev.equals("SW") || abbrev.equals("WS") || abbrev.equals("WF") || abbrev.equals("WX") || abbrev.equals("WN"))
          return "SpectrumWidth";
        else if(abbrev.equals("PN") || abbrev.equals("PS") || abbrev.equals("PF") || abbrev.equals("PX"))
          return "Power";
        else if(abbrev.equals("MN") || abbrev.equals("MS") || abbrev.equals("MF") || abbrev.equals("MX"))
          return "Power";
        else if(abbrev.equals("PH"))
            return "PhiDP";
        else if(abbrev.equals("RH"))
            return "RhoHV";
        else if(abbrev.equals("LH"))
            return "LdrH";
        else if(abbrev.equals("KD"))
            return "KDP";
        else if(abbrev.equals("LV"))
            return "LdrV" ;
        else if(abbrev.equals("DR"))
            return "ZDR";
        else if(abbrev.equals("CZ"))
            return "CorrecteddBZ";
        else if(abbrev.equals("DZ"))
            return "TotalReflectivity";
        else if(abbrev.equals("DR"))
            return "ZDR";
        else
          return abbrev;
    }

   public String getDatatypeUnits(String abbrev) {
       if(abbrev.equals("CZ") || abbrev.equals("DZ") || abbrev.equals("ZN") || abbrev.equals("ZS"))
          return "dBz";
        else if (abbrev.equals("ZF") || abbrev.equals("ZX"))
          return "dBz";
        else if(abbrev.equals("VR") || abbrev.equals("DN") || abbrev.equals("DS") || abbrev.equals("DF") ||abbrev.equals("DX") )
          return "m/s";
        else if(abbrev.equals("VN") || abbrev.equals("VF") )
          return "m/s";
        else if(abbrev.equals("SW") || abbrev.equals("WS") || abbrev.equals("WF") || abbrev.equals("WX") || abbrev.equals("WN"))
          return "m/s";
        else if(abbrev.equals("PN") || abbrev.equals("PS") || abbrev.equals("PF") || abbrev.equals("PX"))
          return "dBM";
        else if(abbrev.equals("MN") || abbrev.equals("MS") || abbrev.equals("MF") || abbrev.equals("MX"))
          return "dBM";

        else
          return abbrev;
   }

    public short getDatatypeRangeFoldingThreshhold(String abbrev) {
        UF_field_header2 header = field_header_map.get(abbrev);
        return header.thresholdValue;
    }

    public float getDatatypeScaleFactor(String abbrev) {
        UF_field_header2 header = field_header_map.get(abbrev);
        return 1.0f/header.scaleFactor;
    }

    public float getDatatypeAddOffset(String abbrev) {
        return 0.0f;
    }


    public int getGateStart(String abbrev) {
        UF_field_header2 header = field_header_map.get(abbrev);
        return header.startRange;
    }

    public int getDataOffset(String abbrev) {
        UF_field_header2 header = field_header_map.get(abbrev);
        return header.dataOffset;

    }
    public int getGateSize(String abbrev) {
        UF_field_header2 header = field_header_map.get(abbrev);
        return header.binSpacing;

    }

    public float getElevation(){
        return uf_header2.elevation/64.f;
    }

    public float getAzimuth(){
        return uf_header2.azimuth/64.f;
    }

    public short getMissingData() {
        return uf_header2.missing;
    }

    public int getYear() {
        return getYear(uf_header2.year) ;
    }

    public float getLatitude(){
        return uf_header2.latitudeD + (uf_header2.latitudeM + uf_header2.latitudeS/(64*60.f))/60.f;
    }

    public float getLongtitude(){
        return uf_header2.longitudeD + (uf_header2.longitudeM + uf_header2.longitudeS/(64*60.f))/60.f;
    }
    
    public float getHorizontalBeamWidth(String abbrev) {
        UF_field_header2 header = field_header_map.get(abbrev);
        return header.HorizontalBeamWidth/64.f;

    }

    public int getYear(int year) {
        if(year > 1970)
            return year;
        if( year > 70 && year < 100)
            return 1900+ year;
        if( year < 60)
            return 2000 + year;

        return 0;
    }

    public long getTitleMsecs() {
        return data_msecs;

    }

    public long setDateMesc() {
        Calendar cal;
        if(uf_header2.timeZone.equals("UT") || uf_header2.timeZone.equals("GM")) {
            cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        }else{
            cal = Calendar.getInstance();
        }
        cal.set(Calendar.YEAR, uf_header2.year);
        cal.set(Calendar.MONTH,uf_header2.month - 1 );
        cal.set(Calendar.DAY_OF_MONTH, uf_header2.day );
        cal.set(Calendar.HOUR_OF_DAY, uf_header2.hour);
        cal.set(Calendar.MINUTE, uf_header2.minute);
        cal.set(Calendar.SECOND, uf_header2.second);

        return cal.getTimeInMillis();
    }

    public Date getDate() {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(data_msecs);
        return cal.getTime();
    }

    class UF_mandatory_header2 {
        String  textUF;
        short   recordSize;   // in 16-bit words
        short   offset2StartOfOptionalHeader; //, origin 1
        short   localUseHeaderPosition;
        short   dataHeaderPosition;
        short   recordNumber;
        short   volumeNumber;       // on tape, n/a for disk
        short   rayNumber;          // within the volume scan
        short   recordNumber1;      // within ray (origin 1)
        short   sweepNumber;        // within the volume scan
        String  radarName;          // char[8]
        String  siteName;           // char[8]
        short   latitudeD;          // degrees (North positive, South negative)
        short   latitudeM;          // minutes
        short   latitudeS;          // seconds*64
        short   longitudeD;         // degrees (East positive, West negative)
        short   longitudeM;         // Minutes
        short   longitudeS;         // Seconds
        short   height;             // of antenna above sea level in meters
        short   year;               // (time of data acquisition)
        short   month ;
        short   day;
        short   hour;
        short   minute;
        short   second;
        String timeZone;            // UT for universal  char[2]
        short   azimuth;            // (degrees*64) of midpoint of sample
        short   elevation;          // (degrees*64)
        short   sweepMode;
            //   0:Cal       1:PPI       2:Coplane 3:RHI
            //   4:Vertical 5:Target 6:Manual 7:Idle
        short   fixedAngle;         // (degrees*64)
        short   sweepRate;          // ((degrees/second)*64)
        short   year1;              // (generation data of UF format)
        short   month1;

        short   day1;
        String  nameOfUFGeneratorProgram; //  char[8]
        short   missing;             // Value stored for deleted or missing data (0x8000)



        UF_mandatory_header2(byte[] data){
            // data is of length 90 bytes
            textUF = new String(data, 0, 2, CDM.utf8Charset);
            if (debug){
                System.out.println(textUF);
            }
            recordSize = getShort(data, 2);
            offset2StartOfOptionalHeader = getShort(data, 4);
            localUseHeaderPosition= getShort(data, 6);
            dataHeaderPosition= getShort(data, 8);
            recordNumber= getShort(data, 10);
            volumeNumber= getShort(data, 12);
            rayNumber= getShort(data, 14);
            recordNumber1= getShort(data, 16);
            sweepNumber= getShort(data, 18);
            radarName= new String(data, 20, 8, CDM.utf8Charset).trim();
            siteName= new String(data, 28, 8, CDM.utf8Charset).trim();
            latitudeD= getShort(data, 36);
            latitudeM= getShort(data, 38);
            latitudeS= getShort(data, 40);
            longitudeD= getShort(data, 42);
            longitudeM= getShort(data, 44);
            longitudeS= getShort(data, 46);
            height= getShort(data, 48);
            int yearValue= getShort(data, 50);
            year = (short)getYear(yearValue);
            month = getShort(data, 52);
            day= getShort(data, 54);
            hour= getShort(data, 56);
            minute= getShort(data, 58);
            second= getShort(data, 60);
            timeZone = new String(data, 62, 2, CDM.utf8Charset);
            azimuth= getShort(data, 64);
            elevation= getShort(data, 66);
            sweepMode= getShort(data, 68);
            fixedAngle= getShort(data, 70);         // (degrees*64)
            sweepRate = getShort(data, 72);          // ((degrees/second)*64)
            year1 = getShort(data, 74);              // (generation data of UF format)
            month1 = getShort(data, 76);
            day1 = getShort(data, 78);
            nameOfUFGeneratorProgram = new String(data, 80, 8,
                    CDM.utf8Charset); //  char[8]
            missing = getShort(data, 88);             // Value stored for deleted or missing data (0x8000)

        }



    }

    class UF_optional_header{

        String    sProjectName;   //  char[8]
        short     iBaselineAzimuth;
        short     iBaselineelevation;
        short     iVolumeScanHour;  /* Time of start of current volume scan */
        short     iVolumeScanMinute;
        short     iVolumeScanSecond;
        String    sFieldTapeName;  // char[8]
        short     iFlag;

        UF_optional_header(byte[] data){
            sProjectName = new String(data, 0, 8, CDM.utf8Charset);
            iBaselineAzimuth = getShort(data, 8);
            iBaselineelevation = getShort(data, 10);
            iVolumeScanHour = getShort(data, 12);
            iVolumeScanMinute = getShort(data, 14);
            iVolumeScanSecond = getShort(data, 16);
            sFieldTapeName = new String(data, 18, 8, CDM.utf8Charset);
            iFlag = getShort(data, 26);
        }

    }


    class UF_field_header2 {

        short   dataOffset;   // from start of record, origin 1
        short   scaleFactor;  // met units = file value/scale
        short   startRange;   // km
        short   startRange1;   // meters
        short   binSpacing;  // in meters
        short   binCount;
        short   pulseWidth;  // in meters
        short   HorizontalBeamWidth; // in degrees*64
        short   verticalBeamWidth; // in degrees*64
        short   receiverBandwidth; // in Mhz*64 ?
        short   polarization;  //:          1:horz   2:vert
        short   waveLength;  // in cm*64
        short   sampleSize;
        String  typeOfData;     //used to threshold  //  char[2]
        short   thresholdValue;
        short   scale;
        String  editCode; //  char[2]
        short   prt;  // in microseconds
        short   bits; // per bin, must be 16
       //         38         12      

        UF_field_header2(byte[] data){
            dataOffset = getShort(data, 0);
            scaleFactor = getShort(data, 2);
            startRange = getShort(data, 4);
            startRange1 = getShort(data, 6);
            binSpacing = getShort(data, 8);
            binCount = getShort(data, 10);
            pulseWidth = getShort(data, 12);
            HorizontalBeamWidth = getShort(data, 14);
            verticalBeamWidth =getShort(data, 16);
            receiverBandwidth = getShort(data, 18);
            polarization = getShort(data, 20);
            waveLength = getShort(data, 22);
            sampleSize = getShort(data, 24);
            typeOfData = new String(data, 26, 2, CDM.utf8Charset);
            thresholdValue = getShort(data, 28);
            scale = getShort(data, 30);
            editCode = new String(data, 32, 2, CDM.utf8Charset);
            prt = getShort(data, 34);
            bits = getShort(data, 36);
        }
    }


    protected short getShort(byte[] bytes, int offset) {

        // careful that we only allow sign extension on the highest order byte
        return (short) bytesToShort(bytes[offset], bytes[offset+1], false);
    }

    public static int bytesToShort(byte a, byte b, boolean swapBytes) {
        // again, high order bit is expressed left into 32-bit form
        if (swapBytes) {
            return (a & 0xff) + ((int)b << 8);
        } else {
            return ((int)a << 8) + (b & 0xff);
        }
    }

    public short[] byte2short(byte [] a, int length){
        int len = length/2;
        short [] b = new short[len];
        byte [] b2 = new byte[2];

        for(int i = 0; i < len; i++){
            b2[0] = a[2*i];
            b2[1] = a[2*i + 1];
            b[i] = getShort(b2, 0);
        }

        return b;
    }

  /**
   * Read data from this ray.
   * @param raf read from this file
   * @param abbrev which data type we want
   * @param gateRange handles the possible subset of data to return
   * @param ii put the data here
   * @throws java.io.IOException
       */
    public void readData(RandomAccessFile raf, String abbrev, Range gateRange, IndexIterator ii) throws IOException {
        long offset = rayOffset;
        offset += (getDataOffset( abbrev) * 2 - 2) ;
        raf.seek(offset);
        byte[] b2 = new byte[2];
        int dataCount = getGateCount( abbrev);
        byte[] data = new byte[dataCount*2];
        raf.readFully(data);

        for (int i = gateRange.first(); i <= gateRange.last(); i += gateRange.stride()) {
            if (i >= dataCount)
                ii.setShortNext(uf_header2.missing);
            else {
                b2[0] = data[i*2];
                b2[1] = data[i*2+1];
                short value = getShort(b2, 0);

                ii.setShortNext(value);
            }
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy