ucar.nc2.iosp.gempak.GempakFileReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of netcdf Show documentation
Show all versions of netcdf Show documentation
The NetCDF-Java Library is a Java interface to NetCDF files,
as well as to many other types of scientific data formats.
/*
* 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.gempak;
import ucar.unidata.io.RandomAccessFile;
import java.io.*;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.Iterator;
import java.util.List;
/**
* Read a Gempak grid file
*/
public class GempakFileReader implements GempakConstants {
/** The file */
protected RandomAccessFile rf;
/** An error message */
private String errorMessage;
/** The label common param */
protected DMLabel dmLabel;
/** header info */
protected List fileHeaderInfo;
/** headers */
protected DMHeaders headers;
/** key */
protected DMKeys keys;
/** part */
protected List parts;
/** the machine type byte order */
protected int MTMACH = RandomAccessFile.BIG_ENDIAN;
/** swap flag */
protected boolean mvmst = false;
/** swap flag */
protected boolean needToSwap = false;
/** file size */
protected long fileSize = 0;
/** masking pattern */
//private static int mskpat = 0xFFFF;
private static int mskpat = ~0;
/**
* Bean ctor
*/
GempakFileReader() {}
/**
* Get a RandomAccessFile for the file location
*
* @param filename filename to read.
* @return RandomAccessFile
*
* @throws IOException problem reading file
*/
public static RandomAccessFile getFile(String filename)
throws IOException {
return new RandomAccessFile(filename, "r", 2048);
}
/**
* Initialize the file, read in all the metadata (ala DM_OPEN)
*
* @param raf RandomAccessFile to read.
* @param fullCheck if true, check entire structure
*
* @return a GempakFileReader
* @throws IOException problem reading file
*/
public static GempakFileReader getInstance(RandomAccessFile raf,
boolean fullCheck)
throws IOException {
GempakFileReader gfr = new GempakFileReader();
gfr.init(raf, fullCheck);
return gfr;
}
/**
* Initialize the file, read in all the metadata (ala DM_OPEN)
*
* @param raf RandomAccessFile to read.
* @param fullCheck if true, check entire structure
*
* @throws IOException problem reading file
*/
public final void init(RandomAccessFile raf, boolean fullCheck)
throws IOException {
setByteOrder();
rf = raf;
raf.seek(0);
boolean ok = init(fullCheck);
fileSize = rf.length();
if ( !ok) {
throw new IOException("Unable to open GEMPAK file: "
+ errorMessage);
}
}
/**
* Initialize this reader. Read all the metadata
*
* @return true if successful
*
* @throws IOException problem reading the data
*/
protected boolean init() throws IOException {
return init(true);
}
/**
* Initialize the file, read in all the metadata (ala DM_OPEN)
*
* @param fullCheck if true, check entire structure
* @return true if successful
*
* @throws IOException problem reading file
*/
protected boolean init(boolean fullCheck) throws IOException {
if (rf == null) {
throw new IOException("file has not been set");
}
dmLabel = new DMLabel();
boolean labelOk = dmLabel.init();
if ( !labelOk) {
logError("not a GEMPAK file");
return false;
}
// Read the keys (DM_RKEY)
readKeys();
if (keys == null) {
logError("Couldn't read keys");
return false;
}
// Read the headers (DM_RHDA)
readHeaders();
if (headers == null) {
logError("Couldn't read headers");
return false;
}
// Read the parts (DM_RPRT)
readParts();
if (parts == null) {
logError("Couldn't read parts");
return false;
}
// Read the file header info (DM_RFIL)
readFileHeaderInfo();
if (fileHeaderInfo == null) {
logError("Couldn't read file header info");
return false;
}
return true;
}
/**
* Get the file name.
* @return the name of the file
*/
public String getFilename() {
return (rf == null)
? null
: rf.getLocation();
}
/**
* Get initial file size
* @return the file size when init was called.
*/
public long getInitFileSize() {
return fileSize;
}
/**
* Get the byte order for this system
*
* @return byte order
*/
public int getByteOrder() {
return MTMACH;
}
/**
* Get the byte order for the machine type.
*
* @param kmachn maching type
*
* @return byte order
*/
public int getByteOrder(int kmachn) {
if ((kmachn == MTVAX) || (kmachn == MTULTX) || (kmachn == MTALPH)
|| (kmachn == MTLNUX) || (kmachn == MTIGPH)) {
return RandomAccessFile.LITTLE_ENDIAN;
}
return RandomAccessFile.BIG_ENDIAN;
}
/**
* Set the machine type for this system.
* @see http://lopica.sourceforge.net/os.html
*/
private void setByteOrder() {
String arch = System.getProperty("os.arch");
if (arch.equals("x86") || // Windows, Linux
arch.equals("arm") || // Window CE
arch.equals("alpha")) { // Utrix, VAX, DECOS
MTMACH = RandomAccessFile.LITTLE_ENDIAN;
} else {
MTMACH = RandomAccessFile.BIG_ENDIAN;
}
}
/**
* Read the file header info (DM_RFIL)
*
* @throws IOException problem reading file
*/
protected void readFileHeaderInfo() throws IOException {
if (dmLabel == null) {
return;
}
int iread = dmLabel.kpfile;
int numheaders = dmLabel.kfhdrs;
String[] names = new String[numheaders];
int[] lens = new int[numheaders];
int[] types = new int[numheaders];
for (int i = 0; i < numheaders; i++) {
names[i] = DM_RSTR(iread++);
}
for (int i = 0; i < numheaders; i++) {
lens[i] = DM_RINT(iread++);
}
for (int i = 0; i < numheaders; i++) {
types[i] = DM_RINT(iread++);
}
fileHeaderInfo = new ArrayList();
for (int i = 0; i < numheaders; i++) {
DMFileHeaderInfo ghi = new DMFileHeaderInfo();
ghi.kfhnam = names[i];
ghi.kfhlen = lens[i];
ghi.kfhtyp = types[i];
fileHeaderInfo.add(ghi);
}
}
/**
* Read in the row and column keys (DM_KEY)
*
* @throws IOException problem reading file
*/
protected void readKeys() throws IOException {
if (dmLabel == null) {
return;
}
keys = new DMKeys();
// read the row keys
int num = dmLabel.krkeys;
List rkeys = new ArrayList(num);
for (int i = 0; i < num; i++) {
String key = DM_RSTR(dmLabel.kprkey + i);
rkeys.add(new Key(key, i, ROW));
}
keys.kkrow = rkeys;
num = dmLabel.kckeys;
List ckeys = new ArrayList(num);
for (int i = 0; i < num; i++) {
String key = DM_RSTR(dmLabel.kpckey + i);
ckeys.add(new Key(key, i, COL));
}
keys.kkcol = ckeys;
}
/** keys to swap */
private static String[] swapKeys = {
"STID", "STD2", "STAT", "COUN", "GPM1", "GVCD"
};
/** number of words to swap */
private static int[] swapNum = {
1, 1, 1, 1, 3, 1
};
/**
* Read the headers (DM_RHDA)
*
* @throws IOException problem reading file
*/
protected void readHeaders() throws IOException {
if (dmLabel == null) {
return;
}
headers = new DMHeaders();
List rowHeaders = new ArrayList(dmLabel.krow);
int istart = dmLabel.kprowh;
// first word is a valid flag so we have to add 1 to size
int[] header;
for (int i = 0; i < dmLabel.krow; i++) {
header = new int[dmLabel.krkeys + 1];
DM_RINT(istart, header);
if (header[0] != IMISSD) {
headers.lstrw = i;
}
rowHeaders.add(header);
istart += header.length;
}
headers.rowHeaders = rowHeaders;
List colHeaders = new ArrayList(dmLabel.kcol);
istart = dmLabel.kpcolh;
for (int i = 0; i < dmLabel.kcol; i++) {
header = new int[dmLabel.kckeys + 1];
DM_RINT(istart, header);
if (header[0] != IMISSD) {
headers.lstcl = i;
}
colHeaders.add(header);
istart += header.length;
}
headers.colHeaders = colHeaders;
// some of the words are characters
if (needToSwap) {
int[] keyLoc = new int[swapKeys.length];
String[] keyType = new String[swapKeys.length];
boolean haveRow = false;
boolean haveCol = false;
for (int i = 0; i < swapKeys.length; i++) {
Key key = findKey(swapKeys[i]);
keyLoc[i] = (key != null)
? key.loc + 1
: 0;
keyType[i] = (key != null)
? key.type
: "";
if (keyType[i].equals(ROW)) {
haveRow = true;
}
if (keyType[i].equals(COL)) {
haveCol = true;
}
}
if (haveRow) {
for (int[] toCheck : headers.rowHeaders) {
for (int j = 0; j < swapKeys.length; j++) {
if (keyType[j].equals(ROW)) {
if (swapKeys[j].equals("GVCD")
&& !(toCheck[keyLoc[j]]
> GempakUtil.vertCoords.length)) {
continue;
}
GempakUtil.swp4(toCheck, keyLoc[j], swapNum[j]);
}
}
}
}
if (haveCol) {
for (int[] toCheck : headers.colHeaders) {
for (int j = 0; j < swapKeys.length; j++) {
if (keyType[j].equals(COL)) {
if (swapKeys[j].equals("GVCD")
&& !(toCheck[keyLoc[j]]
> GempakUtil.vertCoords.length)) {
continue;
}
GempakUtil.swp4(toCheck, keyLoc[j], swapNum[j]);
}
}
}
}
}
}
/**
* Read the parts (DM_RPRT)
*
* @throws IOException problem reading file
*/
protected void readParts() throws IOException {
if (dmLabel == null) {
return;
}
int iread = dmLabel.kppart;
int numParts = dmLabel.kprt;
DMPart[] partArray = new DMPart[numParts];
// read the part names
for (int i = 0; i < numParts; i++) {
partArray[i] = new DMPart();
String partName = DM_RSTR(iread++);
partArray[i].kprtnm = partName;
}
// read the part header lengths
for (int i = 0; i < numParts; i++) {
int headerLen = DM_RINT(iread++);
partArray[i].klnhdr = headerLen;
}
// read the part types
for (int i = 0; i < numParts; i++) {
int partType = DM_RINT(iread++);
partArray[i].ktyprt = partType;
}
// get number of parameters/per part.
for (int i = 0; i < numParts; i++) {
partArray[i].kparms = DM_RINT(iread++);
}
// read parameter names
for (int i = 0; i < numParts; i++) {
int numParms = partArray[i].kparms;
List parms = new ArrayList(numParms);
for (int j = 0; j < numParms; j++) {
DMParam dmp = new DMParam();
parms.add(dmp);
dmp.kprmnm = DM_RSTR(iread++);
}
partArray[i].params = parms;
}
// read the scale
for (int i = 0; i < numParts; i++) {
int numParms = partArray[i].kparms;
List parms = partArray[i].params;
for (int j = 0; j < numParms; j++) {
DMParam dmp = (DMParam) parms.get(j);
dmp.kscale = DM_RINT(iread++);
}
}
// read the offset
for (int i = 0; i < numParts; i++) {
int numParms = partArray[i].kparms;
List parms = partArray[i].params;
for (int j = 0; j < numParms; j++) {
DMParam dmp = (DMParam) parms.get(j);
dmp.koffst = DM_RINT(iread++);
}
}
// read the nbits
for (int i = 0; i < numParts; i++) {
int numParms = partArray[i].kparms;
List parms = partArray[i].params;
for (int j = 0; j < numParms; j++) {
DMParam dmp = (DMParam) parms.get(j);
dmp.kbits = DM_RINT(iread++);
}
}
parts = new ArrayList(numParts);
for (int i = 0; i < numParts; i++) {
parts.add(partArray[i]);
}
for (DMPart part : parts) {
if (part.ktyprt == MDRPCK) {
part.packInfo = new PackingInfo(part);
}
}
}
/**
* Get the byte offset in 0 based space from a 1 based 4 byte
* FORTRAN word.
* @param fortranWord 1 based word offset
* @return byte offset to that word
*/
public static long getOffset(int fortranWord) {
return (fortranWord - 1) * 4l;
}
/**
* Run the program
*
* @param args filename
*
* @throws IOException problem reading the file
*/
public static void main(String[] args) throws IOException {
if (args.length == 0) {
System.out.println("need to supply a GEMPAK grid file name");
System.exit(1);
}
GempakFileReader gfr = getInstance(getFile(args[0]), true);
gfr.printFileLabel();
gfr.printKeys();
gfr.printHeaders();
gfr.printParts();
}
/**
* Class to mimic the GEMPAK DMLABL common block
*/
protected class DMLabel {
/** File identifier */
public static final String DMLABEL = "GEMPAK DATA MANAGEMENT FILE ";
/** version number */
public int kversn;
/** # file headers */
public int kfhdrs;
/** ptr to file keys */
public int kpfile;
/** # of rows */
public int krow;
/** # row keys */
public int krkeys;
/** ptr to row keys */
public int kprkey;
/** ptr to row headers */
public int kprowh;
/** # of cols */
public int kcol;
/** # col keys */
public int kckeys;
/** ptr to col keys */
public int kpckey;
/** ptr to col headers */
public int kpcolh;
/** # of parts */
public int kprt;
/** # part info */
public int kppart;
/** ptr to dmg rec */
public int kpdmgt;
/** length of dmg rec */
public int kldmgt;
/** ptr to data */
public int kpdata;
/** file type */
public int kftype;
/** file source */
public int kfsrce;
/** machine data type */
public int kmachn;
/** int missing data values */
public int kmissd;
/** double missing data values */
public double smissd;
/** swap byte flags */
public boolean kvmst;
/** ieee flags */
public boolean kieeet;
/**
* Create a new DMLabel for the GempakFileReader
*/
public DMLabel() {}
/**
* Read in all the info based on the block of integer words.
* Modeled after DM_RLBL.
*
* @return true if okay.
*
* @throws IOException problem reading the file
*/
public boolean init() throws IOException {
if (rf == null) {
throw new IOException("File is null");
}
rf.order(RandomAccessFile.BIG_ENDIAN);
int mmmm = DM_RINT(26);
if (mmmm > 100) {
mmmm = GempakUtil.swp4(mmmm);
needToSwap = true;
}
//System.out.println("needToSwap = " + needToSwap);
kmachn = mmmm;
mvmst = (getByteOrder() == RandomAccessFile.BIG_ENDIAN);
kvmst = ((kmachn == MTVAX) || (kmachn == MTULTX)
|| (kmachn == MTALPH) || (kmachn == MTLNUX)
|| (kmachn == MTIGPH));
// Set the file values of the missing data values to the current
// system values so that random values will not be converted.
kmissd = IMISSD;
smissd = RMISSD;
String label = DM_RSTR(1, 28);
//System.out.println("label = " + label);
if ( !label.equals(DMLABEL)) {
return false;
}
int[] words = new int[23];
DM_RINT(8, words);
kversn = words[0];
kfhdrs = words[1];
kpfile = words[2];
krow = words[3];
krkeys = words[4];
kprkey = words[5];
kprowh = words[6];
kcol = words[7];
kckeys = words[8];
kpckey = words[9];
kpcolh = words[10];
kprt = words[11];
kppart = words[12];
kpdmgt = words[13];
kldmgt = words[14];
kpdata = words[15];
kftype = words[16];
kfsrce = words[17];
//kmachn = words[18]; // set above
kmissd = words[19];
smissd = DM_RFLT(31);
return true;
}
/**
* Get a String representation of this.
* @return a String representation of this.
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("GEMPAK file label:\n");
buf.append("\tVersion: " + kversn + "\n");
buf.append("\t# File keys: " + kfhdrs + "\n");
buf.append("\tptr to file keys: " + kpfile + "\n");
buf.append("\t# rows: " + krow + "\n");
buf.append("\t# row keys: " + krkeys + "\n");
buf.append("\tptr to row keys: " + kprkey + "\n");
buf.append("\tprt to row header: " + kprowh + "\n");
buf.append("\t# cols: " + kcol + "\n");
buf.append("\t# cols keys: " + kckeys + "\n");
buf.append("\tptr to col keys: " + kpckey + "\n");
buf.append("\tptr to col header: " + kpcolh + "\n");
buf.append("\t# parts: " + kprt + "\n");
buf.append("\tptr part info: " + kppart + "\n");
buf.append("\tptr to data mgmt record: " + kpdmgt + "\n");
buf.append("\tlen of data mgmt record: " + kldmgt + "\n");
buf.append("\tdata pointer: " + kpdata + "\n");
buf.append("\tfile type: " + kftype + "\n");
buf.append("\tfile source: " + kfsrce + "\n");
buf.append("\tmachine type: " + kmachn + "\n");
buf.append("\tinteger missing value: " + kmissd + "\n");
buf.append("\tfloat missing value: " + smissd + "\n");
buf.append("\tswap? " + needToSwap);
return buf.toString();
}
}
/**
* Class to hold the DM File header info
*/
protected class DMFileHeaderInfo {
/** file header name */
public String kfhnam;
/** file header length */
public int kfhlen;
/** file header type */
public int kfhtyp;
/**
* Default ctor
*/
public DMFileHeaderInfo() {}
/**
* Get a String representation of this object.
* @return a String representation of this object.
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Name = ");
buf.append(kfhnam);
buf.append("; length = ");
buf.append(kfhlen);
buf.append("; type = ");
buf.append(kfhtyp);
return buf.toString();
}
}
/**
* Class to mimic the DMKEYS common block.
*/
protected class DMPart {
/** part name */
public String kprtnm;
/** header length */
public int klnhdr;
/** data type */
public int ktyprt;
/** number of params */
public int kparms;
/** list of params */
public List params;
/** packing number */
public int kpkno;
/** length of packed rec */
public int kwordp;
/** packing info */
public PackingInfo packInfo = null;;
/**
* Default ctor
*/
public DMPart() {}
/**
* Get a String representation of this object.
* @return a String representation of this object.
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Part Name = ");
buf.append(kprtnm);
buf.append("; header length = ");
buf.append(klnhdr);
buf.append("; type = ");
buf.append(ktyprt);
buf.append("; packing num = ");
buf.append(kpkno);
buf.append("; packed rec len = ");
buf.append(kwordp);
buf.append("\nParameters: ");
if ((params != null) && !params.isEmpty()) {
for (int i = 0; i < params.size(); i++) {
buf.append("\n " + params.get(i));
}
}
return buf.toString();
}
}
/**
* Class to hold DM Parameter info
*/
protected class DMParam {
/** part name */
public String kprmnm;
/** scaling terms */
public int kscale;
/** offset terms */
public int koffst;
/** # bits */
public int kbits;
/**
* Default ctor
*/
public DMParam() {}
/**
* Get a String representation of this object.
* @return a String representation of this object.
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Param name = ");
buf.append(kprmnm);
buf.append("; scale = ");
buf.append(kscale);
buf.append("; offset = ");
buf.append(koffst);
buf.append("; bits = ");
buf.append(kbits);
return buf.toString();
}
}
/**
* Class to hold DM Integer packing info
*/
protected class PackingInfo {
/** offsets */
public int[] koffst;
/** n bits */
public int[] nbitsc;
/** scaling */
public double[] scalec;
/** missing */
public int[] imissc;
/** missing */
public int[] iswrdc;
/** missing */
public int[] isbitc;
/**
* Set the packing terms for this part
*
* @param part The part for the packing
*/
public PackingInfo(DMPart part) {
List params = part.params;
int numParams = params.size();
koffst = new int[numParams];
nbitsc = new int[numParams];
scalec = new double[numParams];
imissc = new int[numParams];
iswrdc = new int[numParams];
isbitc = new int[numParams];
int i = 0;
int itotal = 0;
for (DMParam param : params) {
koffst[i] = param.koffst;
nbitsc[i] = param.kbits;
scalec[i] = Math.pow(10, param.kscale);
imissc[i] = mskpat >>> (32 - param.kbits);
iswrdc[i] = (itotal / 32);
isbitc[i++] = (itotal % 32) + 1;
itotal += param.kbits;
}
part.kwordp = (itotal - 1) / 32 + 1;
}
/**
* Get a String representation of this object.
* @return a String representation of this object.
* public String toString() {
* StringBuffer buf = new StringBuffer();
* buf.append("Param name = ");
* buf.append(kprmnm);
* buf.append("; scale = ");
* buf.append(kscale);
* buf.append("; offset = ");
* buf.append(koffst);
* buf.append("; bits = ");
* buf.append(kbits);
* return buf.toString();
* }
*/
}
/**
* Class to hold information about a key.
*/
protected class Key {
/** the key name */
public String name;
/** the key location */
public int loc;
/** the key type (ROW or COL) */
public String type;
/**
* Create a new key
*
* @param name the name
* @param loc the location
* @param type the type
*/
public Key(String name, int loc, String type) {
this.name = name;
this.loc = loc;
this.type = type;
}
}
/**
* Class to mimic the DMKEYS common block.
*/
protected class DMKeys {
/** row keys */
public List kkrow;
/** col keys */
public List kkcol;
/**
* Default ctor
*/
public DMKeys() {}
/**
* Get a String representation of this object.
* @return a String representation of this object.
*/
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("\nKeys:\n");
buf.append(" row keys = ");
for (Key key : keys.kkrow) {
buf.append(key.name);
buf.append(", ");
}
buf.append("\n");
buf.append(" column keys = ");
for (Key key : keys.kkcol) {
buf.append(key.name);
buf.append(", ");
}
return buf.toString();
}
}
/**
* Find a key with the given name
*
* @param name the name of the key
*
* @return the key or null;
*/
public Key findKey(String name) {
if (keys == null) {
return null;
}
// search rows
for (Key key : keys.kkrow) {
if (key.name.equals(name)) {
return key;
}
}
// search columns
for (Key key : keys.kkcol) {
if (key.name.equals(name)) {
return key;
}
}
return null;
}
/**
* Class to mimic the DMHDRS common block.
*/
protected class DMHeaders {
/** last valid row */
public int lstrw = 0;
/** last valid column */
public int lstcl = 0;
/** row keys */
public List rowHeaders;
/** column keys */
public List colHeaders;
/**
* Default ctor
*/
public DMHeaders() {}
/**
* Get a String representation of this object.
* @return a String representation of this object.
*/
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("\nHeaders:\n");
if (rowHeaders != null) {
buf.append(" num row headers = ");
buf.append(rowHeaders.size());
buf.append("\n");
}
buf.append(" last row = ");
buf.append(lstrw);
buf.append("\n");
if (colHeaders != null) {
buf.append(" num column headers = ");
buf.append(colHeaders.size());
buf.append("\n");
}
buf.append(" last column = ");
buf.append(lstcl);
return buf.toString();
}
}
/**
* Find the file header with this name
* @param name name of header
* @return headerinfo or null if not found
*/
public DMFileHeaderInfo findFileHeader(String name) {
if ((fileHeaderInfo == null) || fileHeaderInfo.isEmpty()) {
return null;
}
for (Iterator iter = fileHeaderInfo.iterator(); iter.hasNext(); ) {
DMFileHeaderInfo fhi = (DMFileHeaderInfo) iter.next();
if (name.equals(fhi.kfhnam)) {
return fhi;
}
}
return null;
}
/**
* Read in the values for the file header
* @param name name of header
* @return values or null if not found
*
* @throws IOException problem reading file
*/
public float[] getFileHeader(String name) throws IOException {
DMFileHeaderInfo fh = findFileHeader(name);
if ((fh == null) || (fh.kfhtyp != MDREAL)) {
return null;
}
int knt = fileHeaderInfo.indexOf(fh); // 0 based
int iread = dmLabel.kpfile + 3 * dmLabel.kfhdrs;
for (int i = 0; i < knt; i++) {
DMFileHeaderInfo fhi = fileHeaderInfo.get(i);
iread = iread + fhi.kfhlen + 1;
}
int nword = DM_RINT(iread);
if (nword <= 0) {
logError("Invalid header length for " + name);
return null;
}
iread++;
float[] rheader = new float[nword];
if (name.equals("NAVB") && needToSwap) {
DM_RFLT(iread, 1, rheader, 0);
needToSwap = false;
iread++;
DM_RFLT(iread, 1, rheader, 1);
needToSwap = true;
iread++;
DM_RFLT(iread, nword - 2, rheader, 2);
} else {
DM_RFLT(iread, rheader);
}
return rheader;
}
/**
* Log an error
*
* @param errMsg message to log
*/
protected void logError(String errMsg) {
errorMessage = errMsg;
}
/**
* Print the file label
*/
public void printFileLabel() {
if (dmLabel == null) {
return;
}
System.out.println(dmLabel);
}
/**
* Print the row and column keys
*/
public void printKeys() {
if (keys == null) {
return;
}
System.out.println(keys);
}
/**
* Print the row and column keys
*/
public void printHeaders() {
if (headers == null) {
return;
}
System.out.println(headers);
}
/**
* Print the part information
*/
public void printParts() {
if (parts == null) {
return;
}
for (int i = 0; i < parts.size(); i++) {
System.out.println("\nParts[" + i + "]:");
System.out.println(parts.get(i));
}
}
/**
* Find the part with the particular name.
* @param name name of part to find
* @return part number.
*/
public int getPartNumber(String name) {
int part = 0;
if ((parts != null) && !parts.isEmpty()) {
for (int i = 0; i < parts.size(); i++) {
String partName = ((DMPart) parts.get(i)).kprtnm;
if (partName.equals(name)) {
// gotta add 1 because parts are 1 based
part = i + 1;
break;
}
}
}
return part;
}
/**
* Find the part with the particular name.
* @param name name of part to find
* @return part or null if not found
*/
public DMPart getPart(String name) {
if ((parts != null) && !parts.isEmpty()) {
for (int i = 0; i < parts.size(); i++) {
DMPart part = (DMPart) parts.get(i);
String partName = part.kprtnm;
if (partName.equals(name)) {
return part;
}
}
}
return null;
}
/**
* Get the pointer to the data. Taken from DM_RDTR
* @param irow row number
* @param icol column number
* @param partName name of the part
* @return word (1 based) of start of data.
*/
public int getDataPointer(int irow, int icol, String partName) {
int ipoint = -1;
if ((irow < 1) || (irow > dmLabel.krow) || (icol < 1)
|| (icol > dmLabel.kcol)) {
System.out.println("bad row or column number: " + irow + "/"
+ icol);
return ipoint;
}
int iprt = getPartNumber(partName);
if (iprt == 0) {
System.out.println("couldn't find part");
return ipoint;
}
// gotta subtract 1 because parts are 1 but List is 0 based
DMPart part = (DMPart) parts.get(iprt - 1);
// check for valid data type
if ((part.ktyprt != MDREAL) && (part.ktyprt != MDGRID)
&& (part.ktyprt != MDRPCK)) {
System.out.println("Not a valid type");
return ipoint;
}
int ilenhd = part.klnhdr;
ipoint = dmLabel.kpdata + (irow - 1) * dmLabel.kcol * dmLabel.kprt
+ (icol - 1) * dmLabel.kprt + (iprt - 1);
return ipoint;
}
/**
* Read an integer
* @param word word in file (1 based) to read
*
* @return int read
*
* @throws IOException problem reading file
*/
public int DM_RINT(int word) throws IOException {
if (rf == null) {
throw new IOException("DM_RINT: no file to read from");
}
if (dmLabel == null) {
throw new IOException("DM_RINT: reader not initialized");
}
rf.seek(getOffset(word));
// set the order
if (needToSwap) {
//if ((dmLabel.kmachn != MTMACH) &&
// ((dmLabel.kvmst && ! mvmst) ||
// (mvmst && !dmLabel.kvmst))) {
rf.order(RandomAccessFile.LITTLE_ENDIAN); // swap
} else {
rf.order(RandomAccessFile.BIG_ENDIAN);
}
int idata = rf.readInt();
if (IMISSD != dmLabel.kmissd) {
if (idata == dmLabel.kmissd) {
idata = IMISSD;
}
}
rf.order(RandomAccessFile.BIG_ENDIAN);
return idata;
}
/**
* Convenience method to fully read into an array of ints
* @param word word in file (1 based) to read
* @param iarray array to read into
*
*
* @throws IOException problem reading file
*/
public void DM_RINT(int word, int[] iarray) throws IOException {
DM_RINT(word, iarray.length, iarray, 0);
}
/**
* Read into an array of ints.
* @param word word in file (1 based) to read
* @param iarray array to read into
* @param start starting word in the array (0 based)
* @param num number of words to read
*
* @throws IOException problem reading file
*/
public void DM_RINT(int word, int num, int[] iarray, int start)
throws IOException {
for (int i = 0; i < num; i++) {
if (start + i > iarray.length) {
throw new IOException(
"DM_RINT: start+num exceeds iarray length");
}
iarray[start + i] = DM_RINT(word + i);
}
}
/**
* Read a float
* @param word word in file (1 based) to read
*
* @return float read
*
* @throws IOException problem reading file
*/
public float DM_RFLT(int word) throws IOException {
if (rf == null) {
throw new IOException("DM_RFLT: no file to read from");
}
if (dmLabel == null) {
throw new IOException("DM_RFLT: reader not initialized");
}
rf.seek(getOffset(word));
if (needToSwap) {
// set the order
//if ((dmLabel.kmachn != MTMACH) &&
// ((dmLabel.kvmst && ! mvmst) ||
// (mvmst && !dmLabel.kvmst))) {
rf.order(RandomAccessFile.LITTLE_ENDIAN); // swap
} else {
rf.order(RandomAccessFile.BIG_ENDIAN);
}
float rdata = rf.readFloat();
if (RMISSD != dmLabel.smissd) {
if (Math.abs(rdata - dmLabel.smissd) < RDIFFD) {
rdata = RMISSD;
}
}
// reset to read normally
rf.order(RandomAccessFile.BIG_ENDIAN);
return rdata;
}
/**
* Convenience method to fully read into an array of floats
* @param word word in file (1 based) to read
* @param rarray array to read into
*
*
* @throws IOException problem reading file
*/
public void DM_RFLT(int word, float[] rarray) throws IOException {
DM_RFLT(word, rarray.length, rarray, 0);
}
/**
* Read into an array of ints.
* @param word word in file (1 based) to read
* @param num number of words to read
* @param rarray array to read into
* @param start starting word in the array (0 based)
*
* @throws IOException problem reading file
*/
public void DM_RFLT(int word, int num, float[] rarray, int start)
throws IOException {
for (int i = 0; i < num; i++) {
if (start + i > rarray.length) {
throw new IOException(
"DM_RFLT: start+num exceeds rarray length");
}
rarray[start + i] = DM_RFLT(word + i);
}
}
/**
* Read a 4-byte String
* @param isword offset in file (1 based FORTRAN word)
*
* @return String read
*
* @throws IOException problem reading file
*/
public String DM_RSTR(int isword) throws IOException {
return DM_RSTR(isword, 4);
}
/**
* Read a String
* @param isword offset in file (1 based FORTRAN word)
* @param nchar number of characters to read
*
* @return String read
*
* @throws IOException problem reading file
*/
public String DM_RSTR(int isword, int nchar) throws IOException {
if (rf == null) {
throw new IOException("DM_RSTR: no file to read from");
}
rf.seek(getOffset(isword));
return rf.readString(nchar);
}
/**
* Read the data
*
* @param irow row to read
* @param icol column to read
* @param partName part name
*
* @return the header and data array or null;
*
* @throws IOException problem reading file
*/
public RData DM_RDTR(int irow, int icol, String partName)
throws IOException {
return DM_RDTR(irow, icol, partName, 1);
}
/**
* Read the real (float) data
*
* @param irow row to read
* @param icol column to read
* @param partName part name
* @param decimalScale scaling factor (power of 10);
*
* @return the header and data array or null;
*
* @throws IOException problem reading file
*/
public RData DM_RDTR(int irow, int icol, String partName,
int decimalScale)
throws IOException {
int ipoint = -1;
if ((irow < 1) || (irow > dmLabel.krow) || (icol < 1)
|| (icol > dmLabel.kcol)) {
System.out.println("bad row/column number " + irow + "/" + icol);
return null;
}
//System.out.println("reading row " + irow + ", column " + icol);
int iprt = getPartNumber(partName);
if (iprt == 0) {
System.out.println("couldn't find part: " + partName);
return null;
}
// gotta subtract 1 because parts are 1 but List is 0 based
DMPart part = (DMPart) parts.get(iprt - 1);
// check for valid real data type
if ((part.ktyprt != MDREAL) && (part.ktyprt != MDGRID)
&& (part.ktyprt != MDRPCK)) {
System.out.println("Not a valid type");
return null;
}
int ilenhd = part.klnhdr;
ipoint = dmLabel.kpdata + (irow - 1) * dmLabel.kcol * dmLabel.kprt
+ (icol - 1) * dmLabel.kprt + (iprt - 1);
float[] rdata = null;
int[] header = null;
int istart = DM_RINT(ipoint);
if (istart == 0) {
return null;
}
// start catching up here because some files are incorrectly written
try {
int length = DM_RINT(istart);
int isword = istart + 1;
if (length <= ilenhd) {
//System.out.println("length (" + length
// + ") is less than header length (" + ilenhd
// + ")");
return null;
} else if (Math.abs(length) > 10000000) {
//System.out.println("length is huge");
return null;
}
header = new int[ilenhd];
DM_RINT(isword, header);
int nword = length - ilenhd;
isword += header.length;
if (part.ktyprt == MDREAL) {
rdata = new float[nword];
DM_RFLT(isword, rdata);
} else if (part.ktyprt == MDGRID) {
rdata = DM_RPKG(isword, nword, decimalScale);
} else { // packed ints
int[] idata = new int[nword];
DM_RINT(isword, idata);
rdata = DM_UNPK(part, idata);
}
} catch (EOFException eof) {
//System.err.println("reading off end of file");
rdata = null;
}
RData rd = null;
if (rdata != null) {
rd = new RData(header, rdata);
}
return rd;
}
/**
* Unpack an array of packed integers.
*
* @param part the part with packing info
* @param ibitst packed integer bit string
*
* @return unpacked ints as floats
*/
public float[] DM_UNPK(DMPart part, int[] ibitst) {
int nparms = part.kparms;
int nwordp = part.kwordp;
int npack = (int) (ibitst.length - 1) / nwordp + 1;
if (npack * nwordp != ibitst.length) {
//logError("number of packed records not correct");
// System.out.println("number of packed records not correct: "
// + npack * nwordp + " vs. " + ibitst.length);
return null;
}
float[] data = new float[nparms * npack];
PackingInfo pkinf = part.packInfo;
int ir = 0;
int ii = 0;
for (int pack = 0; pack < npack; pack++) {
//
// Move bitstring into internal words. TODO: necessary?
//
int[] jdata = new int[nwordp];
for (int i = 0; i < nwordp; i++) {
jdata[i] = ibitst[ii + i];
}
//
// Extract each data value.
//
for (int idata = 0; idata < nparms; idata++) {
//
// Extract correct bits from words using shift and mask
// operations.
//
int jbit = pkinf.nbitsc[idata];
int jsbit = pkinf.isbitc[idata];
int jshift = 1 - jsbit;
int jsword = pkinf.iswrdc[idata];
int jword = jdata[jsword];
// use >>> to shift avoid carrying sign along
int mask = mskpat >>> (32 - jbit);
int ifield = jword >>> Math.abs(jshift);
ifield = ifield & mask;
if ((jsbit + jbit - 1) > 32) {
jword = jdata[jsword + 1];
jshift = jshift + 32;
int iword = jword << jshift;
iword = iword & mask;
ifield = ifield | iword;
}
//
// The integer data is now in ifield. Use the scaling and
// offset terms to convert to REAL data.
//
if (ifield == pkinf.imissc[idata]) {
data[ir + idata] = RMISSD;
} else {
data[ir + idata] = (ifield + pkinf.koffst[idata])
* (float) pkinf.scalec[idata];
}
}
ir += nparms;
ii += nwordp;
}
return data;
}
/**
* Get a bit string for an integer
*
* @param b the integer
* @return a bit string (e.g.: 01100001|11000000|10011010|10110100|)
*/
protected static String getBits(int b) {
String s = "";
for (int i = 31; i >= 0; i--) {
if ((b & (1 << i)) != 0) {
s = s + "1";
} else {
s = s + "0";
}
if (i % 8 == 0) {
s = s + "|";
}
}
return s;
}
/**
* subclass should implement
*
* @param isword starting word (1 based)
* @param nword number of words to read
* @param decimalScale decimal scale
*
* @return returns null unless subclass overrides
*
* @throws IOException problem reading data
*/
public float[] DM_RPKG(int isword, int nword, int decimalScale)
throws IOException {
return null;
}
/**
* A class to hold real (float) data
*
* @author Unidata Development Team
*/
public class RData {
/** the header */
public int[] header;
/** the data */
public float[] data;
/**
* Create a new holder for the header and data
*
* @param header the header
* @param data the data
*/
public RData(int[] header, float[] data) {
this.header = header;
this.data = data;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy