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

ucar.nc2.iosp.misc.Nldn 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.misc;


import ucar.ma2.*;

import ucar.nc2.*;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants.CF;
import ucar.nc2.util.CancelTask;

import ucar.unidata.io.RandomAccessFile;

import java.io.IOException;

import java.nio.ByteBuffer;


/**
 * National Lightning Detection Network (NLDN)
 *
 * @author caron
 * @see "http://www.unidata.ucar.edu/data/lightning.html"
 * @since Nov 19, 2008
 */
public class Nldn extends AbstractLightningIOSP {

  /*
    Field               Example
    -------------------+---------------------
    date/time (msec)    09/22/93 10:22:33.334
    latitude                            47.33
    longitude                         -87.116
    polarity/signal strength           -188.7
    multiplicity                            6
    ellipse angle                         174
    semi-major axis                       6.0
    eccentricity                          2.0
    chi-square                            1.0

The specifics for the binary NLDN data record contained in the IDD is:

    Size     Name      Description
    --------+---------+----------------------------------------------------
    char[4]  NLDN      'NLDN' marks the start of record
    int[4]   tsec      time in seconds since 1970
    int[4]   nsec      nanoseconds since tsec (seems to be thousandths)
    int[4]   lat       latitude [deg] * 1000
    int[4]   lon       longitude [deg] * 1000
    short[2] fill      padding
    short[2] sgnl      signal strength * 10 [150 NLDN measures ~= 30 kAmps]
    short[2] fill      padding
    short[2] mult      multiplicity [#strokes per flash]
    char[1]  fill      padding
    char[1]  semimaj   semi-major axis
    char[1]  eccent    eccentricity
    char[1]  angle     ellipse angle
    char[1]  chisqr    chi-square

  */

  /**
   * The magic mushroom
   */
  private static final String MAGIC = "NLDN";

  /**
   * The data structure
   */
  private Structure seq;

  /**
   * The structure members
   */
  private StructureMembers sm;

  /**
   * The time in seconds variable name
   */
  private static final String TSEC = "tsec";

  /**
   * The time in nanoseconds from TSEC variable name
   */
  private static final String NSEC = "nsec";

  /**
   * The chi squared variable name
   */
  private static final String CHISQR = "chisqr";

  /**
   * The fill variable name
   */
  private static final String FILL = "fill";

  /**
   * header size
   */
  private static final int recHeader = 84;

  /**
   * record size
   */
  private static final int recSize = 28;

  /**
   * Check if this is a valid file for this IOServiceProvider.
   * You must make this method thread safe, ie dont keep any state.
   *
   * @param raf RandomAccessFile
   * @return true if valid.
   * @throws IOException if read error
   */
  public boolean isValidFile(RandomAccessFile raf) throws IOException {
    raf.seek(0);
    int n = MAGIC.length();
    byte[] b = new byte[n];
    raf.read(b);
    String got = new String(b);
    return got.equals(MAGIC);
  }

  /**
   * Get a unique id for this file type.
   *
   * @return registered id of the file type
   * @see "http://www.unidata.ucar.edu/software/netcdf-java/formats/FileTypes.html"
   */
  public String getFileTypeId() {
    return "NLDN";
  }

  /**
   * Get a human-readable description for this file type.
   *
   * @return description of the file type
   * @see "http://www.unidata.ucar.edu/software/netcdf-java/formats/FileTypes.html"
   */
  public String getFileTypeDescription() {
    return "National Lightning Detection Network";
  }

  /**
   * Open existing file, and populate ncfile with it. This method is only
   * called by the NetcdfFile constructor on itself. The provided NetcdfFile
   * object will be empty except for the location String and the
   * IOServiceProvider associated with this NetcdfFile object.
   *
   * @param raf        the file to work on, it has already passed the
   *                   isValidFile() test.
   * @param ncfile     add objects to this empty NetcdfFile
   * @param cancelTask used to monitor user cancellation; may be null.
   * @throws IOException if read error
   */
  public void open(RandomAccessFile raf, NetcdfFile ncfile, CancelTask cancelTask) throws IOException {
    super.open(raf, ncfile, cancelTask);

    seq = new Sequence(ncfile, null, null, RECORD);
    ncfile.addVariable(null, seq);

    /*
    makeLightningVariable(NetcdfFile ncfile, Group group,
                          Structure seq, String name,
                          DataType dataType, String dims,
                          String longName, String cfName,
                          String units, AxisType type) {
    */
    Variable v = makeLightningVariable(ncfile, null, seq, TSEC, DataType.INT,
                    "", "time of stroke", null,
                    secondsSince1970,
                    AxisType.Time);
    seq.addMemberVariable(v);

    v = makeLightningVariable(ncfile, null, seq, "nsec", DataType.INT,
            "", "nanoseconds since tsec", null,
            "1.0e-9 s", null);
    seq.addMemberVariable(v);

    v = makeLightningVariable(ncfile, null, seq, LAT, DataType.INT, "",
            "latitude", "latitude", CDM.LAT_UNITS,
            AxisType.Lat);
    v.addAttribute(new Attribute(CDM.SCALE_FACTOR, new Float(1.0e-3)));
    seq.addMemberVariable(v);

    v = makeLightningVariable(ncfile, null, seq, LON, DataType.INT, "",
            "longitude", "longitude", CDM.LON_UNITS,
            AxisType.Lon);
    v.addAttribute(new Attribute(CDM.SCALE_FACTOR, new Float(1.0e-3)));
    seq.addMemberVariable(v);

    v = makeLightningVariable(
            ncfile, null, seq, SIGNAL, DataType.SHORT, "",
            "signal strength/polarity [150 NLDN measures ~= 30 kAmps]", null, "",
            null);
    v.addAttribute(new Attribute(CDM.SCALE_FACTOR, new Float(1.0e-1)));
    seq.addMemberVariable(v);

    v = makeLightningVariable(ncfile, null, seq, MULTIPLICITY,
            DataType.BYTE, "",
            "multiplicity [#strokes per flash]", null,
            "", null);
    seq.addMemberVariable(v);

    v = new Variable(ncfile, null, seq, FILL);
    v.setDataType(DataType.BYTE);
    v.setDimensions("");
    seq.addMemberVariable(v);

    v = makeLightningVariable(ncfile, null, seq, MAJOR_AXIS,
            DataType.BYTE, "",
            "error ellipse semi-major axis", null, "",
            null);
    seq.addMemberVariable(v);

    v = makeLightningVariable(ncfile, null, seq, ECCENTRICITY,
            DataType.BYTE, "",
            "error ellipse eccentricity ", null, "",
            null);
    seq.addMemberVariable(v);

    v = makeLightningVariable(ncfile, null, seq, ELLIPSE_ANGLE,
            DataType.BYTE, "",
            "error ellipse axis angle of orientation ",
            null, "degrees", null);
    seq.addMemberVariable(v);

    v = makeLightningVariable(ncfile, null, seq, CHISQR, DataType.BYTE,
            "", "chi-squared", null, "", null);
    seq.addMemberVariable(v);

    addLightningGlobalAttributes(ncfile);

    ncfile.finish();

    sm = seq.makeStructureMembers();
    sm.findMember(TSEC).setDataParam(0);
    sm.findMember(NSEC).setDataParam(4);
    sm.findMember(LAT).setDataParam(8);
    sm.findMember(LON).setDataParam(12);
    sm.findMember(SIGNAL).setDataParam(18);
    sm.findMember(MULTIPLICITY).setDataParam(22);
    sm.findMember(FILL).setDataParam(23);
    sm.findMember(MAJOR_AXIS).setDataParam(24);
    sm.findMember(ECCENTRICITY).setDataParam(25);
    sm.findMember(ELLIPSE_ANGLE).setDataParam(26);
    sm.findMember(CHISQR).setDataParam(27);
    sm.setStructureSize(recSize);
  }

  /**
   * Add the global attributes.
   *
   * @param ncfile the file to add to
   */
  protected void addLightningGlobalAttributes(NetcdfFile ncfile) {
    super.addLightningGlobalAttributes(ncfile);
    ncfile.addAttribute(null,
            new Attribute("title", "NLDN Lightning Data"));

    ncfile.addAttribute(null, new Attribute(CDM.CONVENTIONS, "NLDN-CDM"));
  }

  /* The specifics for the binary NLDN data record contained in the IDD is:

    Size     Name      Description
    --------+---------+----------------------------------------------------
    char[4]  NLDN      'NLDN' marks the start of record
    int[4]   tsec      time in seconds since 1970
    int[4]   nsec      nanoseconds since tsec (seems to be thousandths)
    int[4]   lat       latitude [deg] * 1000
    int[4]   lon       longitude [deg] * 1000
    short[2] fill      padding
    short[2] sgnl      signal strength * 10 [150 NLDN measures ~= 30 kAmps]
    short[2] fill      padding
    short[2] mult      multiplicity [#strokes per flash]
    char[1]  fill      padding
    char[1]  semimaj   semi-major axis
    char[1]  eccent    eccentricity
    char[1]  angle     ellipse angle
    char[1]  chisqr    chi-square
  */

  /* public Array readData(Variable v2, Section section) throws IOException, InvalidRangeException {
  Range r = section.getRange(0);
  int nrecs = r.length();
  byte[] bb = new byte[nrecs * recSize];

  int pos = 0;
  Range.Iterator iter = r.getIterator();
  while (iter.hasNext()) {
    int index = iter.next();
    raf.seek(recHeader + index * recSize);
    raf.read(bb, pos, recSize);
    pos += recSize;
  }

  return new ArrayStructureBB(sm, new int[]{nrecs}, ByteBuffer.wrap(bb), 0);
}  */

  /**
   * Read data from a top level Variable and return a memory resident Array.
   * This Array has the same element type as the Variable, and the requested shape.
   *
   * @param v2      a top-level Variable
   * @param section the section of data to read.
   *                There must be a Range for each Dimension in the variable, in order.
   *                Note: no nulls allowed. IOSP may not modify.
   * @return the requested data in a memory-resident Array
   * @throws IOException           if read error
   * @throws InvalidRangeException if invalid section
   * @see ucar.ma2.Range
   */
  public Array readData(Variable v2, Section section)
          throws IOException, InvalidRangeException {
    return new ArraySequence(sm, new SeqIter(), nelems);
  }

  private int nelems = -1;

  /**
   * Get the structure iterator
   *
   * @param s          the Structure
   * @param bufferSize the buffersize
   * @return the data iterator
   * @throws java.io.IOException if problem reading data
   */
  public StructureDataIterator getStructureIterator(Structure s,
                                                    int bufferSize)
          throws java.io.IOException {
    return new SeqIter();
  }


  /**
   * Sequence Iterator
   *
   * @author Unidata Development Team
   */
  private class SeqIter implements StructureDataIterator {

    /**
     * done?
     */
    private int done = 0;

    /**
     * number bytes already read
     */
    private int alreadyRead = 0;

    /**
     * next index
     */
    private int nextIndex = 0;

    /**
     * the wrapped asbb
     */
    private ArrayStructureBB asbb = null;

    /**
     * total bytes
     */
    private long totalBytes;

    /**
     * bytes read
     */
    private long bytesRead;

    /**
     * Create a new one
     *
     * @throws IOException problem reading the file
     */
    SeqIter() throws IOException {
      totalBytes = (int) raf.length();
      raf.seek(0);
    }

    @Override
    public StructureDataIterator reset() {
      done = 0;
      alreadyRead = 0;
      bytesRead = 0;
      nextIndex = 0;

      try {
        raf.seek(0);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
      return this;
    }

    @Override
    public boolean hasNext() throws IOException {
      if (done < alreadyRead) {
        return true;
      }
      return readHeader();
    }

    @Override
    public StructureData next() throws IOException {
      done++;
      return asbb.getStructureData(nextIndex++);
    }

    /**
     * Read the header
     *
     * @return true if okay
     * @throws IOException problem reading file
     */
    private boolean readHeader() throws IOException {
      if ((bytesRead + recHeader) > totalBytes) {
        nelems = done; // record the number of elements for next time
        return false;
      }

      byte[] b = new byte[recHeader];
      raf.readFully(b);
      bytesRead += recHeader;

      ByteBuffer bb = ByteBuffer.wrap(b);
      int count = bb.getInt(8);
      if (count == 0) {
        return readHeader();
      }

      if ((bytesRead + count * recSize) > totalBytes) {
        return false;
      }
      byte[] data = new byte[count * recSize];
      raf.read(data);
      bytesRead += count * recSize;
      alreadyRead += count;
      nextIndex = 0;

      ByteBuffer bbdata = ByteBuffer.wrap(data);
      asbb = new ArrayStructureBB(sm, new int[]{count}, bbdata, 0);
      return true;
    }

    @Override
    public void setBufferSize(int bytes) {
    }

    @Override
    public int getCurrentRecno() {
      return done - 1;
    }

    @Override
      public void finish() {
        // ignored
      }
  }


  // this is thye start of a buffererd iterator
  /* private class MySDIter implements StructureDataIterator {
   private int done = 0;
   private int readStart = 0;
   private int recsAlreadyRead = 0;
   private int readAtaTime;
   private ArrayStructureBB asbb = null;

   private int recsLeft;
   private int recsDone;

   MySDIter(int bufferSize) throws IOException {
     setBufferSize( bufferSize);
     recsLeft = (int) raf.length() / recSize;
     recsDone = 0;
   }

   public boolean hasNext() {
     if (done < recsAlreadyRead) return true;
     return (recsLeft > 0);
   }

   public StructureDataIterator reset() {
     done = 0;
     readStart = 0;
     readRead = 0;
     return this;
   }

   public StructureData next() throws IOException {
     if (done >= readStart) {
       readNextBuffer();
     }
     done++;
     return asbb.getStructureData( readRead++);
   }

   private void readNextBuffer() throws IOException {
     bytesLeft = (int)(raf.length() - raf.getFilePointer());
     int recsLeft = bytesLeft / recSize;
     int recsToRead = Math.min(recsLeft, readAtaTime);

     byte[] bb = new byte[recsToRead * recSize];
     ByteBuffer.wrap(bb);
     asbb = new ArrayStructureBB(sm, new int[]{nrecs}, bb, 0);

     recsAlreadyRead += recsToRead;
     readRead = 0;
   }

   public void setBufferSize(int bytes) {
     if (done > 0) return; // too late
     if (bytes <= 0)
       bytes = defaultBufferSize;
     readAtaTime = Math.max( 10, bytes / recSize);
   }
 } */


}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy