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

ucar.nc2.iosp.gini.Giniheader 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.

There is a newer version: 4.3.22
Show 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.gini;


import ucar.nc2.*;
import ucar.nc2.units.DateFormatter;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.FeatureType;
import ucar.unidata.geoloc.*;
import ucar.unidata.geoloc.projection.LambertConformal;
import ucar.unidata.geoloc.projection.Stereographic;
import ucar.unidata.geoloc.projection.Mercator;
import ucar.ma2.Array;
import ucar.ma2.DataType;
import ucar.unidata.util.Parameter;

import java.io.*;
import java.util.*;
import java.util.zip.Inflater;
import java.util.zip.DataFormatException;
import java.text.*;
import java.nio.*;


/**
 * Netcdf header reading and writing for version 3 file format.
 * This is used by Giniiosp.
 */

class Giniheader {
    static final byte[] MAGIC = new byte[] {0x43, 0x44, 0x46, 0x01 };
    static final int MAGIC_DIM = 10;
    static final int MAGIC_VAR = 11;
    static final int MAGIC_ATT = 12;
    private boolean debug = false, debugPos = false, debugString = false, debugHeaderSize = false;
    private ucar.unidata.io.RandomAccessFile raf;
    private ucar.nc2.NetcdfFile ncfile;
   // private PrintStream out = System.out;
    static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Giniheader.class);
    int numrecs = 0; // number of records written
    int recsize = 0; // size of each record (padded)
    int dataStart = 0; // where the data starts
    int recStart = 0; // where the record data starts
    int GINI_PIB_LEN = 21;   // gini product indentification block
    int GINI_PDB_LEN = 512;  // gini product description block
    int GINI_HED_LEN = 533;  // gini product header
    double DEG_TO_RAD = 0.017453292;
    double EARTH_RAD_KMETERS = 6371.200;
    byte Z_DEFLATED = 8;
    byte DEF_WBITS = 15;
    private long actualSize, calcSize;
    protected int Z_type = 0;



    public boolean isValidFile( ucar.unidata.io.RandomAccessFile raf)
    {
        try{
             return validatePIB( raf );
        }
        catch ( IOException e )
        {
            return false;

        }
    }

  /**
   * Read the header and populate the ncfile
   * @param raf
   * @throws IOException
   */
    boolean validatePIB(ucar.unidata.io.RandomAccessFile raf ) throws IOException {
        this.raf = raf;
        this.actualSize = raf.length();
        int pos = 0;
        raf.seek(pos);

        // gini header process
        byte[] b = new byte[GINI_PIB_LEN + GINI_HED_LEN];

        raf.read(b);
        String pib = new String(b);

        pos = pib.indexOf( "KNES" );
        if ( pos == -1 ) pos = pib.indexOf ( "CHIZ" );

        if ( pos != -1 ) {                    /* 'KNES' or 'CHIZ' found         */
            pos = pib.indexOf ( "\r\r\n" );    /* <<<<< UPC mod 20030710 >>>>>   */
            if ( pos != -1 ) {                 /* CR CR NL found             */
              pos  = pos + 3;
            }
        } else {
            pos = 0;
            return false;
        }
            return true;
    }


  /**
   * Read the header and populate the ncfile
   * @param raf
   * @throws IOException
   */
   byte[] readPIB(ucar.unidata.io.RandomAccessFile raf ) throws IOException {
    this.raf = raf;
    this.actualSize = raf.length();
    int doff = 0;
    int pos = 0;
    raf.seek(pos);

    // gini header process
    byte[] b = new byte[GINI_PIB_LEN + GINI_HED_LEN];
    byte[] buf = new byte[GINI_HED_LEN ];
    byte[] head = new byte[GINI_PDB_LEN ];

    raf.read(b);
    String pib = new String(b);

    //if( !pib.startsWith("TICZ")) return (int)pos; // gini header start with TICZ 99....

    pos = pib.indexOf( "KNES" );
    if ( pos == -1 ) pos = pib.indexOf ( "CHIZ" );

    if ( pos != -1 ) {                    /* 'KNES' or 'CHIZ' found         */
       pos = pib.indexOf ( "\r\r\n" );    /* <<<<< UPC mod 20030710 >>>>>   */
       if ( pos != -1 ) {                 /* CR CR NL found             */
          pos  = pos + 3;
       }
    } else {
      pos = 0;
    }

    dataStart = pos + GINI_PDB_LEN;

    // Test the next two bytes to see if the image portion looks like
    // it is zlib-compressed
    byte[] b2 = new byte[2];
    b2[0] = b[pos];
    b2[1] = b[pos+1];
    Inflater inflater = new Inflater( false);
    int resultLength = 0;
    int inflatedLen = 0;
    int pos1 = 0;

    if( isZlibHed( b2 ) == 1) {
       Z_type = 1;
       inflater.setInput(b, pos, GINI_HED_LEN );
       try {
            resultLength = inflater.inflate(buf, 0, GINI_HED_LEN);
       }
       catch (DataFormatException ex) {
          log.warn("ERROR on inflation "+ex.getMessage());
          ex.printStackTrace();
          throw new IOException( ex.getMessage());
       }

       if(resultLength != GINI_HED_LEN )System.out.println("Zlib inflated image header size error");
       inflatedLen = GINI_HED_LEN - inflater.getRemaining();

       String inf = new String(buf);
       pos1 = inf.indexOf( "KNES" );
       if ( pos1 == -1 ) pos1 = inf.indexOf ( "CHIZ" );

       if ( pos1 != -1 ) {                    /* 'KNES' or 'CHIZ' found         */
          pos1 = inf.indexOf ( "\r\r\n" );    /* <<<<< UPC mod 20030710 >>>>>   */
          if ( pos1 != -1 ) {                 /* CR CR NL found             */
            pos1  = pos1 + 3;
          }
       } else {
          pos1 = 0;
       }

       System.arraycopy(buf, pos1, head, 0, GINI_PDB_LEN );
       dataStart = pos + inflatedLen;

    } else {
       System.arraycopy(b, pos, head, 0, GINI_PDB_LEN );
    }

    if( pos == 0 && pos1 == 0 ) return null;

    return head;

  }

  void read(ucar.unidata.io.RandomAccessFile raf, ucar.nc2.NetcdfFile ncfile, PrintStream out) throws IOException {
    this.raf = raf;
    this.ncfile = ncfile;
    int        proj;                        /* projection type indicator     */
                                            /* 1 - Mercator                  */
                                            /* 3 - Lambert Conf./Tangent Cone*/
                                            /* 5 - Polar Stereographic       */

    int        ent_id;                      /* GINI creation entity          */
    int        sec_id;                      /* GINI sector ID                */
    int        phys_elem;                   /* 1 - Visible, 2- 3.9IR, 3 - 6.7IR ..*/
    int        nx;
    int        ny;
    int        pole;
    int        gyear;
    int        gmonth;
    int        gday;
    int        ghour;
    int        gminute;
    int        gsecond;
    double     lonv;                        /* meridian parallel to y-axis */
    double     diff_lon;
    double     lon1 = 0.0, lon2 = 0.0;
    double     lat1 = 0.0, lat2 = 0.0;
    double     latt = 0.0, lont = 0.0;
    double     imageScale = 0.0;
    //long       hoff = 0;


    // long pos = GINI_PIB_LEN;
    byte [] head = readPIB(raf );
    ByteBuffer bos = ByteBuffer.wrap(head);
    //if (out != null) this.out = out;
    actualSize = raf.length();

    Attribute att = new Attribute( "Conventions", "GRIB");
    this.ncfile.addAttribute(null, att);

    bos.position(0);
    byte[] b2 = new byte[2];

    //sat_id = (int )( raf.readByte());
    Byte nv = new Byte(bos.get());
    att = new Attribute( "source_id", nv);
    this.ncfile.addAttribute(null, att);

    nv = new Byte( bos.get());
    ent_id = nv.intValue();
    att = new Attribute( "entity_id", nv);
    this.ncfile.addAttribute(null, att);

    nv = new Byte( bos.get());
    sec_id = nv.intValue();
    att = new Attribute( "sector_id", nv);
    this.ncfile.addAttribute(null, att);

    nv = new Byte ( bos.get());
    phys_elem = nv.intValue();
    att = new Attribute( "phys_elem", nv);
    this.ncfile.addAttribute(null, att);

    bos.position(bos.position() + 4);

    gyear = (int) ( bos.get());
      gyear += ( gyear < 50 ) ? 2000 : 1900;
    gmonth = (int) ( bos.get());
    gday = (int) ( bos.get());
    ghour = (int) ( bos.get());
    gminute = (int) ( bos.get());
    gsecond = (int) ( bos.get());

    DateFormat dformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    dformat.setTimeZone(java.util.TimeZone.getTimeZone("GMT"));
    Calendar cal = Calendar.getInstance();
    cal.set(gyear, gmonth-1, gday, ghour, gminute, gsecond);
    cal.setTimeZone(java.util.TimeZone.getTimeZone("GMT"));
    String dstring = dformat.format(cal.getTime());

    Dimension dimT  = new Dimension( "time", 1, true, false, false);
    ncfile.addDimension( null, dimT);

    String timeCoordName = "time";
    Variable taxis = new Variable(ncfile, null, null, timeCoordName);
    taxis.setDataType(DataType.DOUBLE);
    taxis.setDimensions("time");
    taxis.addAttribute( new Attribute("long_name", "time since base date"));
    taxis.addAttribute( new Attribute(_Coordinate.AxisType, AxisType.Time.toString()));
    double [] tdata = new double[1];
    tdata[0] = cal.getTimeInMillis();
    Array dataA = Array.factory(DataType.DOUBLE.getPrimitiveClassType(), new int[] {1}, tdata);
    taxis.setCachedData( dataA, false);
    DateFormatter formatter = new DateFormatter();
    taxis.addAttribute( new Attribute("units", "msecs since "+formatter.toDateTimeStringISO(new Date(0))));
    ncfile.addVariable(null, taxis);

    //att = new Attribute( "Time", dstring);
    //this.ncfile.addAttribute(null, att);
    this.ncfile.addAttribute(null, new Attribute("time_coverage_start", dstring));
    this.ncfile.addAttribute(null, new Attribute("time_coverage_end", dstring));
    bos.get();   /* skip a byte for hundreds of seconds */

    nv   = new Byte ( bos.get());
    att = new Attribute( "ProjIndex", nv);
    this.ncfile.addAttribute(null, att);
    proj = nv.intValue();
    if( proj == 1) {
     att = new Attribute( "ProjName", "MERCATOR");
    } else if (proj == 3) {
     att = new Attribute( "ProjName", "LAMBERT_CONFORNAL");
    } else if (proj == 5) {
     att = new Attribute( "ProjName", "POLARSTEREOGRAPHIC");
    }

    this.ncfile.addAttribute(null, att);

    /*
    ** Get grid dimensions
    */

    byte[] b3 = new byte[3];
    bos.get(b2, 0, 2);
    nx = getInt( b2, 2);
    Integer ni = new Integer(nx);
    att = new Attribute( "NX", ni);
    this.ncfile.addAttribute(null, att);


    bos.get(b2, 0, 2);
    ny = getInt( b2, 2);
    ni = new Integer(ny);
    att = new Attribute( "NY", ni);
    this.ncfile.addAttribute(null, att);

    ProjectionImpl projection = null;
    double dxKm = 0.0, dyKm = 0.0, latin, lonProjectionOrigin ;

    switch( proj ) {

      case 1:                                                    /* Mercator */
        /*
        ** Get the latitude and longitude of first and last "grid" points
        */

        /* Latitude of first grid point */
        bos.get(b3, 0, 3);
        int nn = getInt( b3, 3);
        lat1 = (double) nn / 10000.0;
        Double nd = new Double(lat1);
        att = new Attribute( "Latitude0", nd);
        this.ncfile.addAttribute(null, att);

        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        int b33 = (int)(b3[0] & (1<< 7));
      //  if( b33 == 128)      //west longitude
      //      nd = new Double(((double) nn) / 10000.0 * (-1));
      //  else
            nd = new Double(((double) nn) / 10000.0 );
        lon1 = nd.doubleValue();
        att = new Attribute( "Longitude0", nd);
        this.ncfile.addAttribute(null, att);

        /* Longitude of last grid point */
        bos.get(); /* skip one byte */

        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        nd = new Double( ((double) nn) / 10000.0);
        lat2 = nd.doubleValue();
        att = new Attribute( "LatitudeN", nd);
        this.ncfile.addAttribute(null, att);

        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        b33 = (int)(b3[0] & (1<< 7));
       // if( b33 == 128)      //west longitude
      //      nd = new Double(((double) nn) / 10000.0 * (-1));
      //  else
            nd = new Double(((double) nn) / 10000.0 );
        lon2 = nd.doubleValue();
        att = new Attribute( "LongitudeN", nd);
        this.ncfile.addAttribute(null, att);

        /*
        ** Hack to catch incorrect sign of lon2 in header.
        */

    //    if ( lon1 > 0.0 && lon2 < 0.0 ) lon2 *= -1;
        double lon_1 = lon1;
        double lon_2 = lon2;
        if ( lon1 < 0 ) lon_1 += 360.0;
        if ( lon2 < 0 ) lon_2 += 360.0;

        lonv = lon_1 - (lon_1 - lon_2) / 2.0;

        if ( lonv >  180.0 ) lonv -= 360.0;
        if ( lonv < -180.0 ) lonv += 360.0;
        /*
        ** Get the "Latin" parameter.  The ICD describes this value as:
        ** "Latin - The latitude(s) at which the Mercator projection cylinder
        ** intersects the earth."  It should read that this is the latitude
        ** at which the image resolution is that defined by octet 41.
        */
        bos.getInt(); /* skip 4 bytes */
        bos.get();    /* skip 1 byte */

        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        nd = new Double(((double) nn) / 10000.0);

        /* Latitude of proj cylinder intersects */
        att = new Attribute( "LatitudeX", nd);
        latin = nd.doubleValue();
        this.ncfile.addAttribute(null, att);

        latt = 0.0; // this is not corrected  // jc 8/7/08 not used

       // dyKm =  Math.cos( DEG_TO_RAD*latt);
       // dxKm = DEG_TO_RAD * EARTH_RAD_KMETERS * Math.abs((lon_1-lon_2) / (nx-1));
      //  double dy  =  EARTH_RAD_KMETERS * Math.cos(DEG_TO_RAD*latt) / (ny - 1);
      //  dyKm = dy *( Math.log( Math.tan(DEG_TO_RAD*( (lat2-latt)/2.0 + 45.0 ) ) )
      //                  -Math.log( Math.tan(DEG_TO_RAD*( (lat1-latt)/2.0 + 45.0 ) ) ) );
      //  dxKm = DEG_TO_RAD * EARTH_RAD_KMETERS * Math.abs(lon1-lon2) / (ny-1);
        projection = new Mercator( lonv, latin) ;
        break;

      case 3:                               /* Lambert Conformal             */
      case 5:                               /* Polar Stereographic           */
        /*
        ** Get lat/lon of first grid point
        */
        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        nd = new Double(((double) nn) / 10000.0);
        lat1 = nd.doubleValue();
        //att = new Attribute( "Lat1", nd);
        //this.ncfile.addAttribute(null, att);
        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        nd = new Double(((double) nn) / 10000.0);
        lon1 = nd.doubleValue();
        /*
        ** Get Lov - the orientation of the grid; i.e. the east longitude of
        ** the meridian which is parallel to the y-aixs
        */
        bos.get(); /* skip one byte */

        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        nd = new Double(((double) nn) / 10000.0);
        lonv = nd.doubleValue();
        lonProjectionOrigin = lonv;
        att = new Attribute( "Lov", nd);
        this.ncfile.addAttribute(null, att);

        /*
        ** Get distance increment of grid
        */
        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        dxKm = ((double) nn) / 10000.0;

        nd = new Double(((double) nn) / 10000.);
        att = new Attribute( "DxKm", nd);
        this.ncfile.addAttribute(null, att);

        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        dyKm = ((double) nn) / 10000.0;

        nd = new Double( ((double) nn) / 10000.);
        att = new Attribute( "DyKm", nd);
        this.ncfile.addAttribute(null, att);
        /* calculate the lat2 and lon2 */

        if ( proj == 5 ) {
            latt = 60.0;            /* Fixed for polar stereographic */
            imageScale = (1. + Math.sin(DEG_TO_RAD*latt))/2.;
        }

        lat2 = lat1 + dyKm*(ny-1) / 111.26;


        /* Convert to east longitude */
        if ( lonv < 0. ) lonv += 360.;
        if ( lon1 < 0. ) lon1 += 360.;


        lon2 = lon1 + dxKm*(nx-1) / 111.26 * Math.cos(DEG_TO_RAD*lat1);

        diff_lon = lonv - lon1;

        if ( diff_lon >  180. )  diff_lon -= 360.;
        if ( diff_lon < -180. )  diff_lon += 360.;
        /*
        ** Convert to normal longitude to McIDAS convention
        */
        lonv = (lonv > 180.) ? -(360.-lonv) : lonv;
        lon1 = (lon1 > 180.) ? -(360.-lon1) : lon1;
        lon2 = (lon2 > 180.) ? -(360.-lon2) : lon2;
        /*
        ** Check high bit of octet for North or South projection center
        */
        nv= new Byte(bos.get());
        pole = nv.intValue();
        pole = ( pole > 127 ) ? -1 : 1;
        ni = new Integer(pole);
        att = new Attribute( "ProjCenter", ni);
        this.ncfile.addAttribute(null, att);

        bos.get(); /* skip one byte for Scanning mode */

        bos.get(b3, 0, 3);
        nn = getInt( b3, 3);
        latin = (((double) nn) / 10000.);

        nd = new Double(((double) nn) / 10000.);
        att = new Attribute( "Latin", nd);
        this.ncfile.addAttribute(null, att);

        if (proj == 3 )
          projection = new LambertConformal(latin, lonProjectionOrigin, latin, latin);
        else // (proj == 5)
          projection = new Stereographic(90.0, lonv, imageScale);

        break;

      default:
        System.out.println("unimplemented projection");


    }


    this.ncfile.addAttribute(null, new Attribute("title", gini_GetEntityID( ent_id )));
    this.ncfile.addAttribute(null, new Attribute("summary", getPhysElemSummary(phys_elem, ent_id)));
    this.ncfile.addAttribute(null, new Attribute("id", gini_GetSectorID(sec_id)));
    this.ncfile.addAttribute(null, new Attribute("keywords_vocabulary", gini_GetPhysElemID(phys_elem, ent_id)));
    this.ncfile.addAttribute(null, new Attribute("cdm_data_type", FeatureType.GRID.toString()));
    this.ncfile.addAttribute(null, new Attribute("standard_name_vocabulary", getPhysElemLongName(phys_elem, ent_id)));
    this.ncfile.addAttribute(null, new Attribute("creator_name", "UNIDATA"));
    this.ncfile.addAttribute(null, new Attribute("creator_url", "http://www.unidata.ucar.edu/"));
    this.ncfile.addAttribute(null, new Attribute("naming_authority", "UCAR/UOP"));
    this.ncfile.addAttribute(null, new Attribute("geospatial_lat_min", new Float(lat1)));
    this.ncfile.addAttribute(null, new Attribute("geospatial_lat_max", new Float(lat2)));
    this.ncfile.addAttribute(null, new Attribute("geospatial_lon_min", new Float(lon1)));
    this.ncfile.addAttribute(null, new Attribute("geospatial_lon_max", new Float(lon2)));
    //this.ncfile.addAttribute(null, new Attribute("geospatial_vertical_min", new Float(0.0)));
    //this.ncfile.addAttribute(null, new Attribute("geospatial_vertical_max", new Float(0.0)));

    /** Get the image resolution.
    */

    bos.position(41);  /* jump to 42 bytes of PDB */
    nv = new Byte( ( bos.get() ) );      /* Res [km] */
    att = new Attribute( "imageResolution", nv);
    this.ncfile.addAttribute(null, att);
   // if(proj == 1)
   //     dyKm = nv.doubleValue()/dyKm;
    /* compression flag 43 byte */

    nv = new Byte( ( bos.get() ));      /* Res [km] */
    att = new Attribute( "compressionFlag", nv );
    this.ncfile.addAttribute(null, att);

    if ( convertunsignedByte2Short( nv.byteValue() ) == 128 )
    {
       Z_type = 2;
       //out.println( "ReadNexrInfo:: This is a Z file ");
    }

   /* new 47 - 60 */
    bos.position(46);
    nv = new Byte( ( bos.get() ) );      /* Cal indicator */
    int navcal = convertunsignedByte2Short(nv);
    int [] calcods = null;
    if(navcal == 128)
        calcods = getCalibrationInfo(bos, phys_elem, ent_id);

    // only one data variable per gini file

    String vname= gini_GetPhysElemID(phys_elem, ent_id);
    Variable var = new Variable( ncfile, ncfile.getRootGroup(), null, vname);
    var.addAttribute( new Attribute("long_name", getPhysElemLongName(phys_elem, ent_id)));
    var.addAttribute( new Attribute("units", getPhysElemUnits(phys_elem, ent_id)));
    // var.addAttribute( new Attribute("missing_value", new Byte((byte) 0))); // ??

      // get dimensions
    int velems;
    boolean isRecord = false;
    ArrayList dims = new ArrayList();

    Dimension dimX  = new Dimension( "x", nx, true, false, false);
    Dimension dimY  = new Dimension( "y", ny, true, false, false);

    ncfile.addDimension( null, dimY);
    ncfile.addDimension( null, dimX);

    velems = dimX.getLength() * dimY.getLength();
    dims.add( dimT);
    dims.add( dimY);
    dims.add( dimX);

    var.setDimensions( dims);

    // size and beginning data position in file
    int vsize = velems;
    long begin = dataStart ;
    if (debug) log.warn(" name= "+vname+" vsize="+vsize+" velems="+velems+" begin= "+begin+" isRecord="+isRecord+"\n");
    if( navcal == 128) {
        var.setDataType( DataType.FLOAT);
        var.setSPobject( new Vinfo (vsize, begin, isRecord, nx, ny, calcods));
     /*   var.addAttribute(new Attribute("_Unsigned", "true"));
        int numer = calcods[0] - calcods[1];
        int denom = calcods[2] - calcods[3];
        float a  = (numer*1.f) / (1.f*denom);
        float b  = calcods[0] - a * calcods[2];
        var.addAttribute( new Attribute("scale_factor", new Float(a)));
        var.addAttribute( new Attribute("add_offset", new Float(b)));
      */
    }
    else  {
        var.setDataType( DataType.BYTE);
        var.addAttribute(new Attribute("_Unsigned", "true"));
        var.addAttribute(new Attribute("_missing_value", new Short((short)255)));
        var.addAttribute( new Attribute("scale_factor", new Short((short)(1))));
        var.addAttribute( new Attribute("add_offset", new Short((short)(0))));
        var.setSPobject( new Vinfo (vsize, begin, isRecord, nx, ny));
    }
    String coordinates = "x y time";
    var.addAttribute( new Attribute(_Coordinate.Axes, coordinates));
    ncfile.addVariable(null, var);

    // add coordinate information. we need:
    // nx, ny, dx, dy,
    // latin, lov, la1, lo1

    // we have to project in order to find the origin
    ProjectionPointImpl start = (ProjectionPointImpl) projection.latLonToProj( new LatLonPointImpl( lat1, lon1));
    if (debug) log.warn("start at proj coord "+start);

    double startx = start.getX();
    double starty = start.getY();

    // create coordinate variables
    Variable xaxis = new Variable( ncfile, null, null, "x");
    xaxis.setDataType( DataType.DOUBLE);
    xaxis.setDimensions( "x");
    xaxis.addAttribute( new Attribute("long_name", "projection x coordinate"));
    xaxis.addAttribute( new Attribute("units", "km"));
    xaxis.addAttribute( new Attribute(_Coordinate.AxisType, "GeoX"));
    double[] data = new double[nx];
    if( proj == 1 ) {
        double lon_1 = lon1;
        double lon_2 = lon2;
        if ( lon1 < 0 ) lon_1 += 360.0;
        if ( lon2 < 0 ) lon_2 += 360.0;
        double dx = (lon_2 - lon_1) /(nx-1);

        for (int i = 0; i < data.length; i++) {
          double ln = lon1 + i * dx;
          ProjectionPointImpl pt = (ProjectionPointImpl) projection.latLonToProj( new LatLonPointImpl( lat1, ln));
          data[i] = pt.getX();  // startx + i*dx;
        }
    } else {
        for (int i = 0; i < data.length; i++)
          data[i] = startx + i*dxKm;
    }

    dataA = Array.factory(DataType.DOUBLE.getPrimitiveClassType(), new int[] {nx}, data);
    xaxis.setCachedData( dataA, false);
    ncfile.addVariable(null, xaxis);

    Variable yaxis = new Variable( ncfile, null, null, "y");
    yaxis.setDataType( DataType.DOUBLE);
    yaxis.setDimensions( "y");
    yaxis.addAttribute( new Attribute("long_name", "projection y coordinate"));
    yaxis.addAttribute( new Attribute("units", "km"));
    yaxis.addAttribute( new Attribute(_Coordinate.AxisType, "GeoY"));
    data = new double[ny];
    double endy = starty + dyKm * (data.length - 1); // apparently lat1,lon1 is always the lower ledt, but data is upper left
    if(proj == 1) {
        double dy = (lat2 - lat1 ) / (ny-1);
        for (int i = 0; i < data.length; i++) {
          double la = lat2 - i*dy;
          ProjectionPointImpl pt = (ProjectionPointImpl) projection.latLonToProj( new LatLonPointImpl( la, lon1));
          data[i] = pt.getY();  //endyy - i*dy;
        }
    }
    else {
        for (int i = 0; i < data.length; i++)
          data[i] = endy - i*dyKm;
    }
    dataA = Array.factory(DataType.DOUBLE.getPrimitiveClassType(), new int[] {ny}, data);
    yaxis.setCachedData( dataA, false);
    ncfile.addVariable(null, yaxis);

    // coordinate transform variable
    Variable ct = new Variable( ncfile, null, null, projection.getClassName());
    ct.setDataType( DataType.CHAR);
    ct.setDimensions( "");
    List params = projection.getProjectionParameters();
    for (int i = 0; i < params.size(); i++) {
      Parameter p = (Parameter) params.get(i);
      ct.addAttribute( new Attribute(p));
    }
    ct.addAttribute( new Attribute(_Coordinate.TransformType, "Projection"));
    ct.addAttribute( new Attribute(_Coordinate.Axes, "x y "));
    // fake data
    dataA = Array.factory(DataType.CHAR.getPrimitiveClassType(), new int[] {});
    dataA.setChar(dataA.getIndex(), ' ');
    ct.setCachedData(dataA, false);

    ncfile.addVariable(null, ct);
    ncfile.addAttribute( null, new Attribute("Conventions", _Coordinate.Convention));

    // finish
    ncfile.finish();
  }

  int [] getCalibrationInfo(ByteBuffer bos, int phys_elem, int ent_id){

    bos.position(46);
    byte nv = new Byte( ( bos.get() ) );      /* Cal indicator */
    int navcal = convertunsignedByte2Short(nv);
    int [] calcods = null;
    if( navcal == 128 ) {    /* Unidata Cal block found; unpack values */
        int      scale=10000;
        int      jscale=100000000;
        byte  [] unsb = new byte[8];
        byte[] b4 = new byte[4];
        bos.get(unsb);
        String unitStr = new String(unsb).toUpperCase();
        String iname;
        String iunit;
        bos.position(55);
        nv = new Byte( ( bos.get() ) );
        int calcod = convertunsignedByte2Short(nv);

        if ( unitStr.contains("INCH") ) {
            iname = new String( "RAIN" );
            iunit = new String( "IN  ");

        } else if ( unitStr.contains("dBz" ) ) {
            iname = new String( "ECHO" );
            iunit = new String( "dBz " );

        } else if (unitStr.contains("KFT" ) ) {

            iname = new String( "TOPS");
            iunit = new String( "KFT ");

        } else if ( unitStr.contains("KG/M" ) ) {

            iname = new String( "VIL " );
            iunit = new String( "mm  " );

        } else {

            iname = new String( "    " );
            iunit = new String( "    " );
        }

        if ( calcod > 0 ) {
            calcods = new int[5*calcod + 1];
            calcods[0] = calcod;
            for (int i = 0; i < calcod; i++ ) {

                bos.position(56+i*16);
                bos.get(b4);
                int minb = getInt(b4, 4) / 10000;        /* min brightness values         */
                bos.get(b4);
                int maxb = getInt(b4, 4 ) / 10000;       /* max brightness values         */
                bos.get(b4);
                int mind = getInt(b4, 4 );               /* min data values               */
                bos.get(b4);
                int maxd = getInt(b4, 4 );               /* max data values               */

                int idscal = 1;
                while ( !(mind % idscal != 0) && !(maxd % idscal != 0) ) {
                    idscal *= 10;
                }
                idscal /= 10;

                if ( idscal < jscale ) jscale = idscal;

                calcods[1+i*5] = mind;
                calcods[2+i*5] = maxd;
                calcods[3+i*5] = minb;
                calcods[4+i*5] = maxb;
                calcods[5+i*5] = 0;

            }

           if ( jscale > scale ) jscale = scale;
                scale /= jscale;

            if ( gini_GetPhysElemID(phys_elem, ent_id).contains("Precipitation") ) {
                if ( scale < 100 ) {
                    jscale /= (100/scale);
                    scale   = 100;
                }
            }

            for (int i = 0; i < calcod; i++ ) {
                calcods[1+i*5] /= jscale;
                calcods[2+i*5] /= jscale;
                calcods[5+i*5]  = scale;
            }

      }

    }

    return calcods;
      
  }


  int gini_GetCompressType( )
  {
       return Z_type;
  }

  // Return the string of entity ID for the GINI image file

  String gini_GetSectorID(int ent_id )
  {
    String name;
     /* GINI channel ID          */

    switch( ent_id ) {
      case 0:
        name = "Northern Hemisphere Composite";
        break;
      case 1:
        name = "East CONUS";
        break;
      case 2:
        name = "West CONUS";
        break;
      case 3:
        name = "Alaska Regional" ;
        break;
      case 4:
        name = "Alaska National" ;
        break;
      case 5:
        name = "Hawaii Regional";
        break;
      case 6:
        name = "Hawaii National";
        break;
      case 7:
        name = "Puerto Rico Regional";
        break;
      case 8:
        name = "Puerto Rico National";
        break;
      case 9:
        name = "Supernational";
        break;
      case 10:
        name = "NH Composite - Meteosat/GOES E/ GOES W/GMS";
        break;
      default:
        name = "Unknown-ID";
	}

   return name;


  }

  // Return the channel ID for the GINI image file
  String gini_GetEntityID(int ent_id )
  {
    String name;
      switch ( ent_id ) {
           case 99:
             name = "RADAR-MOSIAC Composite Image";
             break;
           case 6:
             name = "Composite";
             break;
           case 7:
             name = "DMSP satellite Image";
             break;
           case 8:
             name = "GMS satellite Image";
             break;
           case 9:                                    /* METEOSAT (using 6)       */
             name = "METEOSAT satellite Image" ;
             break;
           case 10:                                   /* GOES-7                   */
             name = "GOES-7 satellite Image";
             break;
           case 11:                                   /* GOES-8                   */
             name = "GOES-8 satellite Image";
             break;
           case 12:                                   /* GOES-9                   */
             name = "GOES-9 satellite Image";
             break;
           case 13:                                   /* GOES-10                  */
             name = "GOES-10 satellite Image" ;
             break;
           case 14:                                   /* GOES-11                  */
             name = "GOES-11 satellite Image" ;
             break;
           case 15:                                   /* GOES-12                  */
             name = "GOES-12 satellite Image";
             break;
           case 16:                                   /* GOES-13                  */
             name = "GOES-13 satellite Image";
             break;
           default:
             name = "Unknown";
         }

   return name;


  }
  // Return the channel ID for the GINI image file
  String gini_GetPhysElemID(int phys_elem, int ent_id )
  {
    String name;

    switch( phys_elem ) {
      case 1:
        name = "VIS";
        break;
      case 3:
        name = "IR_WV";
        break;
      case 2:
      case 4:
      case 5:
      case 6:
      case 7:
        name = "IR" ;
        break;
      case 13:
        name = "LI" ;
        break;
      case 14:
        name = "PW" ;
        break;
      case 15:
        name = "SFC_T" ;
        break;
      case 16:
        name = "LI" ;
        break;
      case 17:
        name = "PW" ;
        break;
      case 18:
        name = "SFC_T" ;
        break;
      case 19:
        name = "CAPE" ;
        break;
      case 20:
        name = "T" ;
        break;
      case 21:
        name = "WINDEX" ;
        break;
      case 22:
        name = "DMPI" ;
        break;
      case 23:
        name = "MDPI" ;
        break;
      case 25:
        if( ent_id == 99)
            name = "Reflectivity";
        else
            name = "Volcano_imagery";
        break;
      case 27:
        if(ent_id == 99 )
            name = "Reflectivity";
        else
            name = "CTP";
        break;
      case 28:
        if(ent_id == 99 )
            name = "Reflectivity";
        else
            name = "Cloud_Amount";
        break;
      case 26:
        name = "EchoTops";
        break;
      case 29:
        name = "VIL";
        break;
      case 30:
      case 31:
        name = "Precipitation";
        break;
      case 40:
      case 41:
      case 42:
      case 43:
      case 44:
      case 45:
      case 46:
      case 47:
      case 48:
      case 49:
      case 50:
      case 51:
      case 52:
      case 53:
      case 54:
      case 55:
      case 56:
      case 57:
      case 58:
        name = "sounder_imagery";
        break;
      case 59:
        name = "VIS_sounder";
        break;
      default:
        name = "Unknown";
	}

   return name;


  }


  // ??
  String getPhysElemUnits(int phys_elem, int ent_id ) {
    switch( phys_elem ) {
      case 1:
      case 3:
      case 2:
      case 4:
      case 5:
      case 6:
      case 7:
      case 13:
      case 14:
      case 15:
      case 16:
      case 17:
      case 18:
      case 19:
      case 20:
      case 21:
      case 22:
      case 23:
      case 29:
      case 43:
      case 48:
      case 50:
      case 51:
      case 52:
      case 55:
      case 57:
      case 59: return  "N/A";
      case 26: return  "K FT";
      case 25:
        if( ent_id == 99)
            return "dBz";
        else
            return  "N/A";
      case 27:
        if( ent_id == 99)
            return "dBz";
        else
          return  "N/A";
      case 28:
        if( ent_id == 99)
            return "dBz";
        else
          return  "N/A";
      case 30: return "IN";
      case 31: return "IN";
      default: return "Unknown";
    }
  }

  // Return the channel ID for the GINI image file

  String getPhysElemLongName(int phys_elem, int ent_id ) {
     switch( phys_elem ) {
      case 1:
        return "Imager Visible";
      case 2:
        return "Imager 3.9 micron IR";
      case 3:
        return "Imager 6.7/6.5 micron IR (WV)";
      case 4:
        return "Imager 11 micron IR" ;
      case 5:
        return "Imager 12 micron IR" ;
      case 6:
        return "Imager 13 micron IR";
      case 7:
        return "Imager 1.3 micron IR";
      case 13:
        return  "Lifted Index LI" ;
      case 14:
        return  "Precipitable Water PW" ;
      case 15:
        return  "Surface Skin Temperature";
      case 16:
        return  "Lifted Index LI" ;
      case 17:
        return  "Precipitable Water PW" ;
      case 18:
        return  "Surface Skin Temperature" ;
      case 19:
        return  "Convective Available Potential Energy" ;
      case 20:
        return  "land-sea Temperature" ;
      case 21:
        return  "Wind Index" ;
      case 22:
        return  "Dry Microburst Potential Index" ;
      case 23:
        return  "Microburst Potential Index" ;
      case 25:
        if( ent_id == 99)
            return "2 km National 248 nm Base Composite Reflectivity";
        else
            return "Volcano_imagery";
      case 26:
        return "4 km National Echo Tops";
      case 27:
        if( ent_id == 99)
            return "1 km National Base Reflectivity Composite (Unidata)";
        else
            return "Cloud Top Pressure or Height";
      case 28:
        if( ent_id == 99)
            return "1 km National Composite Reflectivity (Unidata)";
        else
            return "Cloud Amount";

      case 29:
        return "4 km National Vertically Integrated Liquid Water";
      case 30:
        return "2 km National 1-hour Precipitation (Unidata)";
      case 31:
        return "4 km National Storm Total Precipitation (Unidata)";
      case 43:
        return "14.06 micron sounder image";
      case 48:
        return "11.03 micron sounder image";
      case 50:
        return "7.43 micron sounder image";
      case 51:
        return "7.02 micron sounder image" ;
      case 52:
        return "6.51 micron sounder image" ;
      case 55:
        return "4.45 micron sounder image";
      case 57:
        return "3.98 micron sounder image";
      case 59:
        return  "VIS sounder image ";
      default:
       return "unknown physical element "+ phys_elem;
    }
  }

  String getPhysElemSummary(int phys_elem, int ent_id ) {
     switch( phys_elem ) {
      case 1:
        return "Satellite Product Imager Visible";
      case 2:
        return "Satellite Product Imager 3.9 micron IR";
      case 3:
        return "Satellite Product Imager 6.7/6.5 micron IR (WV)";
      case 4:
        return "Satellite Product Imager 11 micron IR" ;
      case 5:
        return "Satellite Product Imager 12 micron IR" ;
      case 6:
        return "Satellite Product Imager 13 micron IR";
      case 7:
        return "Satellite Product Imager 1.3 micron IR";
      case 13:
        return  "Imager Based Derived Lifted Index LI" ;
      case 14:
        return  "Imager Based Derived Precipitable Water PW" ;
      case 15:
        return  "Imager Based Derived Surface Skin Temperature" ;
      case 16:
        return  "Sounder Based Derived Lifted Index LI" ;
      case 17:
        return  "Sounder Based Derived Precipitable Water PW" ;
      case 18:
        return  "Sounder Based Derived Surface Skin Temperature" ;
      case 19:
        return  "Derived Convective Available Potential Energy CAPE" ;
      case 20:
        return  "Derived land-sea Temperature" ;
      case 21:
        return  "Derived Wind Index WINDEX" ;
      case 22:
        return  "Derived Dry Microburst Potential Index DMPI" ;
      case 23:
        return  "Derived Microburst Day Potential Index MDPI" ;
      case 43:
        return "Satellite Product 14.06 micron sounder image";
      case 48:
        return "Satellite Product 11.03 micron sounder image";
      case 50:
        return "Satellite Product 7.43 micron sounder image";
      case 51:
        return "Satellite Product 7.02 micron sounder image" ;
      case 52:
        return "Satellite Product 6.51 micron sounder image" ;
      case 55:
        return "Satellite Product 4.45 micron sounder image";
      case 57:
        return "Satellite Product 3.98 micron sounder image";
      case 59:
        return "Satellite Product VIS sounder visible image ";
      case 25:
        if( ent_id == 99)
            return "Nexrad Level 3 National 248 nm Base Composite Reflectivity at Resolution 2 km";
        else
            return "Satellite Derived Volcano_imagery";

      case 26:
          return "Nexrad Level 3 National Echo Tops at Resolution 4 km";
      case 29: return "Nexrad Level 3 National Vertically Integrated Liquid Water at Resolution 4 km";
      case 28:
         if( ent_id == 99)
            return "Nexrad Level 3 National 248 nm Base Composite Reflectivity at Resolution 2 km";
         else
            return "Gridded Cloud Amount";
      case 27:
          if( ent_id == 99)
            return "Nexrad Level 3 Base Reflectivity National Composition at Resolution 1 km";
        else
            return "Gridded Cloud Top Pressure or Height";

      case 30: return "Nexrad Level 3 1 hour precipitation National Composition at Resolution 2 km";
      case 31: return "Nexrad Level 3 total precipitation National Composition at Resolution 4 km";
      default: return "unknown";
    }

  }


/*
** Name:       GetInt
**
** Purpose:    Convert GINI 2 or 3-byte quantities to int
**
*/
  int getInt( byte[] b, int num )
  {
      int            base=1;
      int            i;
      int            word=0;

      int bv[] = new int[num];

      for (i = 0; i 127 )
      {
         bv[0] -= 128;
         base = -1;
      }
      /*
      ** Calculate the integer value of the byte sequence
      */

      for ( i = num-1; i >= 0; i-- ) {
        word += base * bv[i];
        base *= 256;
      }

      return word;

  }

  public short convertunsignedByte2Short(byte b)
  {
     return (short)((b<0)? (short)b + 256 : (short)b);
  }


// this converts a byte array to a wrapped primitive (Byte, Short, Integer, Double, Float, Long)
  protected Object convert( byte[] barray, DataType dataType, int byteOrder) {

    if (dataType == DataType.BYTE) {
      return new Byte( barray[0]);
    }

    if (dataType == DataType.CHAR) {
      return new Character((char) barray[0]);
    }

    ByteBuffer bbuff = ByteBuffer.wrap( barray);
    if (byteOrder >= 0)
      bbuff.order( byteOrder == ucar.unidata.io.RandomAccessFile.LITTLE_ENDIAN? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);

    if (dataType == DataType.SHORT) {
      ShortBuffer tbuff = bbuff.asShortBuffer();
      return new Short(tbuff.get());

    } else if (dataType == DataType.INT) {
      IntBuffer tbuff = bbuff.asIntBuffer();
      return new Integer(tbuff.get());

    } else if (dataType == DataType.LONG) {
      LongBuffer tbuff = bbuff.asLongBuffer();
      return new Long(tbuff.get());

    } else if (dataType == DataType.FLOAT) {
      FloatBuffer tbuff = bbuff.asFloatBuffer();
      return new Float(tbuff.get());

    } else if (dataType == DataType.DOUBLE) {
      DoubleBuffer tbuff = bbuff.asDoubleBuffer();
      return new Double(tbuff.get());
    }

    throw new IllegalStateException();
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////////

  // variable info for reading/writing
  class Vinfo {
    int vsize; // size of array in bytes. if isRecord, size per record.
    long begin; // offset of start of data from start of file
    boolean isRecord; // is it a record variable?
    int nx;
    int ny;
    int [] levels;

    Vinfo( int vsize, long begin, boolean isRecord, int x, int y) {
      this.vsize = vsize;
      this.begin = begin;
      this.isRecord = isRecord;
      this.nx = x;
      this.ny = y;
    }

    Vinfo( int vsize, long begin, boolean isRecord, int x, int y, int[] levels) {
      this.vsize = vsize;
      this.begin = begin;
      this.isRecord = isRecord;
      this.nx = x;
      this.ny = y;
      this.levels = levels;
    }
     
  }


  int isZlibHed( byte[] buf ){
    short b0 = convertunsignedByte2Short(buf[0]);
    short b1 = convertunsignedByte2Short(buf[1]);

    if ( (b0 & 0xf) == Z_DEFLATED ) {
      if ( (b0 >> 4) + 8 <= DEF_WBITS ) {
        if ( (((b0 << 8) + b1) % 31)==0 ) {
          return 1;
        }
      }
    }

    return 0;

  }

}
/* Change History:
   $Log: Giniheader.java,v $
   Revision 1.15  2005/10/11 18:44:11  yuanho
   change missing value attribute to variable

   Revision 1.14  2005/10/11 18:09:06  yuanho
   adding missing value attribute

   Revision 1.13  2005/10/11 15:25:05  yuanho
   variable naming changes for satellite data

   Revision 1.12  2005/10/10 21:02:56  yuanho
   adding changes for satellite data

   Revision 1.11  2005/07/28 21:46:36  yuanho
   remove the static from Vinfo class

   Revision 1.10  2005/07/12 23:00:58  yuanho
   remove static, add global attr

   Revision 1.9  2005/05/11 00:10:03  caron
   refactor StuctureData, dt.point

   Revision 1.8  2004/12/15 22:35:25  caron
   add _unsigned

   Revision 1.7  2004/12/07 22:13:28  yuanho
   add phyElem for 1hour and total precipitation

   Revision 1.6  2004/12/07 22:13:15  yuanho
   add phyElem for 1hour and total precipitation

   Revision 1.5  2004/12/07 01:29:31  caron
   redo convention parsing, use _Coordinate encoding.

   Revision 1.4  2004/10/29 00:14:11  caron
   no message

   Revision 1.3  2004/10/19 15:17:22  yuanho
   gini header DxKm update

   Revision 1.2  2004/10/15 23:18:34  yuanho
   gini projection update

   Revision 1.1  2004/10/13 22:57:57  yuanho
   no message

   Revision 1.4  2004/08/16 20:53:45  caron
   2.2 alpha (2)

   Revision 1.3  2004/07/12 23:40:17  caron
   2.2 alpha 1.0 checkin

   Revision 1.2  2004/07/06 19:28:10  caron
   pre-alpha checkin

   Revision 1.1.1.1  2003/12/04 21:05:27  caron
   checkin 2.2

 */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy