ucar.nc2.iosp.gempak.GempakStationFileIOSP 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.ma2.*;
import ucar.nc2.*;
import ucar.nc2.constants.CF;
import ucar.nc2.iosp.AbstractIOServiceProvider;
import ucar.nc2.units.DateFormatter;
import ucar.nc2.util.CancelTask;
import ucar.unidata.io.RandomAccessFile;
import visad.util.Trace;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* An IOSP for Gempak Station (SF,SN) data.
*
* @author Unidata Java Development Team
*/
public abstract class GempakStationFileIOSP extends AbstractIOServiceProvider {
/** The netCDF file */
protected NetcdfFile ncfile;
/** the file we are reading */
protected RandomAccessFile raf;
/** Gempak file reader */
protected AbstractGempakStationFileReader gemreader;
/** place to store debug stuff */
protected StringBuilder parseInfo = new StringBuilder();
/** data formatter */
private DateFormatter dateFormat = new DateFormatter();
/** Float missing attribute */
protected final static Number RMISS = new Float(GempakConstants.RMISSD);
/** Integer missing attribute */
protected final static Number IMISS = new Integer(GempakConstants.IMISSD);
/** static for shared dimension of length 4 */
protected final static Dimension DIM_LEN8 = new Dimension("len8", 8,
true);
/** static for shared dimension of length 4 */
protected final static Dimension DIM_LEN4 = new Dimension("len4", 4,
true);
/** static for shared dimension of length 2 */
protected final static Dimension DIM_LEN2 = new Dimension("len2", 2,
true);
/** name for the time variable */
protected final static String TIME_VAR = "time";
/** name for the time variable */
protected final static String MISSING_VAR = "_isMissing";
/** station variable names */
private static String[] stnVarNames = {
GempakStation.STID, GempakStation.STNM, GempakStation.SLAT,
GempakStation.SLON, GempakStation.SELV, GempakStation.STAT,
GempakStation.COUN, GempakStation.STD2, GempakStation.SPRI,
GempakStation.SWFO, GempakStation.WFO2
};
/** lengths of station variable */
private static int[] stnVarSizes = {
8, 4, 4, 4, 4, 2, 2, 4, 4, 4, 4
};
/**
* Is this a valid file?
*
* @param raf RandomAccessFile to check
*
* @return true if a valid Gempak grid file
*
* @throws IOException problem reading file
*/
public boolean isValidFile(RandomAccessFile raf) throws IOException {
try {
gemreader = makeStationReader();
Trace.call1("GEMPAKSIOSP.isValidFile: reader.init");
gemreader.init(raf, false);
Trace.call2("GEMPAKSIOSP.isValidFile: reader.init");
} catch (Exception ioe) {
return false;
}
return true;
}
/**
* Make the appropriate station file reader, subclasses need to implement
* this
*
* @return the appropriate reader for that subclass
*/
protected abstract AbstractGempakStationFileReader makeStationReader();
/**
* Open the service provider for reading.
* @param raf file to read from
* @param ncfile netCDF file we are writing to (memory)
* @param cancelTask task for cancelling
*
* @throws IOException problem reading file
*/
public void open(RandomAccessFile raf, NetcdfFile ncfile,
CancelTask cancelTask)
throws IOException {
//System.out.printf("GempakSurfaceIOSP open %s (%s) %n", raf.getLocation(), Calendar.getInstance().getTime());
this.raf = raf;
this.ncfile = ncfile;
long start = System.currentTimeMillis();
if (gemreader == null) {
gemreader = makeStationReader();
}
Trace.call1("GEMPAKStationIOSP.open: initTables");
initTables();
Trace.call2("GEMPAKStationIOSP.open: initTables");
Trace.call1("GEMPAKStationIOSP.open: reader.init");
gemreader.init(raf, true);
Trace.call2("GEMPAKStationIOSP.open: reader.init");
buildNCFile();
}
/**
* Initialize the parameter tables.
*/
private void initTables() {
try {
GempakParameters.addParameters(
"resources/nj22/tables/gempak/params.tbl");
} catch (Exception e) {
System.out.println("unable to init param tables");
}
}
/**
* Close this IOSP
*
* @throws IOException problem closing file
*/
public void close() throws IOException {
raf.close();
}
/**
* Sync and extend
*
* @return false
*/
public boolean syncExtend() {
return false;
}
/**
* Get the detail information
*
* @return the detail info
*/
public String getDetailInfo() {
return parseInfo.toString();
}
/**
* Sync the file
*
* @return true if needed to sync
*
* @throws IOException problem synching the file
*/
public boolean sync() throws IOException {
//printStack("***************************** sync ************************", 100);
//System.out.printf("check sync on %s (%s) %n", raf.getLocation(), Calendar.getInstance().getTime());
if (gemreader.getInitFileSize() < raf.length()) {
long start = System.currentTimeMillis();
Trace.msg("GEMPAKStationIOSP.sync: file " + raf.getLocation()
+ " is bigger: " + raf.length() + " > "
+ gemreader.getInitFileSize());
Trace.call1("GEMPAKStationIOSP.sync: reader.init");
gemreader.init(raf, true);
Trace.call2("GEMPAKStationIOSP.sync: reader.init");
Trace.call1("GEMPAKStationIOSP.sync: buildNCFile");
// reconstruct the ncfile objects
buildNCFile();
Trace.call2("GEMPAKSIOSP.sync: buildNCFile");
//System.out.printf("sync on %s took %d msecs%n", raf.getLocation(), (System.currentTimeMillis()-start));
return true;
}
return false;
}
/**
* Build the netCDF file
*
* @throws IOException problem reading the file
*/
protected void buildNCFile() throws IOException {
Trace.call1("GEMPAKSIOSP: buildNCFile");
ncfile.empty();
fillNCFile();
addGlobalAttributes();
ncfile.finish();
Trace.call2("GEMPAKSIOSP: buildNCFile");
//System.out.println(ncfile);
}
/**
* Fill the contents of the netCDF file. Assumes that the file has been
* cleared.
*
* @throws IOException problem reading the file
*/
protected abstract void fillNCFile() throws IOException;
/**
* Make a structure for the part
*
* @param partName partname
* @param dimensions dimensions for the structure
* @param includeMissing true to include the missing variable
*
* @return a Structure
*/
protected Structure makeStructure(String partName, List dimensions,
boolean includeMissing) {
List params = gemreader.getParameters(partName);
if (params == null) {
return null;
}
Structure sVar = new Structure(ncfile, null, null, partName);
sVar.setDimensions(dimensions);
for (GempakParameter param : params) {
sVar.addMemberVariable(makeParamVariable(param, null));
}
if (includeMissing) {
sVar.addMemberVariable(makeMissingVariable());
}
return sVar;
}
/**
* Make the missing variable
*
* @return the missing variable
*/
protected Variable makeMissingVariable() {
Variable var = new Variable(ncfile, null, null, MISSING_VAR);
var.setDataType(DataType.BYTE);
var.setDimensions((List) null);
var.addAttribute(
new Attribute(
"description",
"missing flag - 1 means all params are missing"));
var.addAttribute(new Attribute("missing_value", new Byte((byte) 1)));
return var;
}
/**
* Make a variable from a GempakParmaeter
*
* @param param GempakParameter
* @param dims Variable dimensions
*
* @return the Variable
*/
protected Variable makeParamVariable(GempakParameter param,
List dims) {
Variable var = new Variable(ncfile, null, null, param.getName());
var.setDataType(DataType.FLOAT);
var.setDimensions(dims);
var.addAttribute(new Attribute("long_name", param.getDescription()));
String units = param.getUnit();
if ((units != null) && !units.equals("")) {
var.addAttribute(new Attribute("units", units));
}
var.addAttribute(new Attribute("missing_value", RMISS));
return var;
}
/**
* Add on global attributes for all types
*/
protected void addGlobalAttributes() {
// global stuff
ncfile.addAttribute(null,
new Attribute("Conventions", getConventions()));
String fileType = "GEMPAK " + gemreader.getFileType();
ncfile.addAttribute(null, new Attribute("file_format", fileType));
ncfile.addAttribute(null,
new Attribute("history",
"Direct read of " + fileType
+ " into NetCDF-Java 4.1 API")); // at " + dateFormat.toDateTimeStringISO(new Date())));
ncfile.addAttribute(null, new Attribute(CF.featureTypeAtt, getCFFeatureType()));
}
/**
* Get the netCDF conventions identifier.
* @return the convention name
*/
public String getConventions() {
return "GEMPAK/CDM";
}
/**
* Get the CF feature type, subclasses should override
* @return the feature type
*/
public String getCFFeatureType() {
return CF.FeatureType.point.toString();
}
/**
* Get the size of a particular station variable
*
* @param name name of the variable (key)
*
* @return size or -1
*/
protected int getStnVarSize(String name) {
int size = -1;
for (int i = 0; i < stnVarNames.length; i++) {
if (name.equals(stnVarNames[i])) {
size = stnVarSizes[i];
break;
}
}
return size;
}
/**
* Make the station variables from a representative station
*
* @param stations list of stations
* @param dim station dimension
*
* @return the list of variables
*/
protected List makeStationVars(List stations,
Dimension dim) {
int numStations = stations.size();
boolean useSTID = true;
for (GempakStation station : stations) {
if (station.getSTID().equals("")) {
useSTID = false;
break;
}
}
List vars = new ArrayList();
List stnKeyNames = gemreader.getStationKeyNames();
for (String varName : stnKeyNames) {
Variable v = makeStationVariable(varName, dim);
// use STNM or STID as the name or description
Attribute stIDAttr = new Attribute("standard_name", "station_id");
if (varName.equals(GempakStation.STID) && useSTID) {
v.addAttribute(stIDAttr);
}
if (varName.equals(GempakStation.STNM) && !useSTID) {
v.addAttribute(stIDAttr);
}
vars.add(v);
}
// see if we fill these in completely now
if ((dim != null) && (numStations > 0)) {
for (Variable v : vars) {
Array varArray;
if (v.getDataType().equals(DataType.CHAR)) {
int[] shape = v.getShape();
varArray = new ArrayChar.D2(shape[0], shape[1]);
} else {
varArray = get1DArray(v.getDataType(), numStations);
}
int index = 0;
String varname = v.getName();
for (GempakStation stn : stations) {
String test = "";
if (varname.equals(GempakStation.STID)) {
test = stn.getName();
} else if (varname.equals(GempakStation.STNM)) {
((ArrayInt.D1) varArray).set(index,
// (int) (stn.getSTNM() / 10));
(int) (stn.getSTNM()));
} else if (varname.equals(GempakStation.SLAT)) {
((ArrayFloat.D1) varArray).set(index,
(float) stn.getLatitude());
} else if (varname.equals(GempakStation.SLON)) {
((ArrayFloat.D1) varArray).set(index,
(float) stn.getLongitude());
} else if (varname.equals(GempakStation.SELV)) {
((ArrayFloat.D1) varArray).set(index,
(float) stn.getAltitude());
} else if (varname.equals(GempakStation.STAT)) {
test = stn.getSTAT();
} else if (varname.equals(GempakStation.COUN)) {
test = stn.getCOUN();
} else if (varname.equals(GempakStation.STD2)) {
test = stn.getSTD2();
} else if (varname.equals(GempakStation.SPRI)) {
((ArrayInt.D1) varArray).set(index, stn.getSPRI());
} else if (varname.equals(GempakStation.SWFO)) {
test = stn.getSWFO();
} else if (varname.equals(GempakStation.WFO2)) {
test = stn.getWFO2();
}
if ( !test.equals("")) {
((ArrayChar.D2) varArray).setString(index, test);
}
index++;
}
v.setCachedData(varArray, false);
}
}
return vars;
}
/**
* Get a 1DArray for the type and length
*
* @param type DataType
* @param len length
*
* @return the array
*/
private Array get1DArray(DataType type, int len) {
Array varArray = null;
if (type.equals(DataType.FLOAT)) {
varArray = new ArrayFloat.D1(len);
} else if (type.equals(DataType.DOUBLE)) {
varArray = new ArrayDouble.D1(len);
} else if (type.equals(DataType.INT)) {
varArray = new ArrayInt.D1(len);
}
return varArray;
}
/**
* Make a station variable
*
* @param varname variable name
* @param firstDim station dimension
*
* @return corresponding variable
*/
protected Variable makeStationVariable(String varname,
Dimension firstDim) {
String longName = varname;
String unit = null;
DataType type = DataType.CHAR;
List dims = new ArrayList();
List attrs = new ArrayList();
if (firstDim != null) {
dims.add(firstDim);
}
if (varname.equals(GempakStation.STID)) {
longName = "Station identifier";
dims.add(DIM_LEN8);
} else if (varname.equals(GempakStation.STNM)) {
longName = "WMO station id";
type = DataType.INT;
} else if (varname.equals(GempakStation.SLAT)) {
longName = "latitude";
unit = "degrees_north";
type = DataType.FLOAT;
attrs.add(new Attribute("standard_name", "latitude"));
} else if (varname.equals(GempakStation.SLON)) {
longName = "longitude";
unit = "degrees_east";
type = DataType.FLOAT;
attrs.add(new Attribute("standard_name", "longitude"));
} else if (varname.equals(GempakStation.SELV)) {
longName = "altitude";
unit = "meter";
type = DataType.FLOAT;
attrs.add(new Attribute("positive", "up"));
attrs.add(new Attribute("standard_name", "station_altitude"));
} else if (varname.equals(GempakStation.STAT)) {
longName = "state or province";
dims.add(DIM_LEN2);
} else if (varname.equals(GempakStation.COUN)) {
longName = "country code";
dims.add(DIM_LEN2);
} else if (varname.equals(GempakStation.STD2)) {
longName = "Extended station id";
dims.add(DIM_LEN4);
} else if (varname.equals(GempakStation.SPRI)) {
longName = "Station priority";
type = DataType.INT;
} else if (varname.equals(GempakStation.SWFO)) {
longName = "WFO code";
dims.add(DIM_LEN4);
} else if (varname.equals(GempakStation.WFO2)) {
longName = "Second WFO code";
dims.add(DIM_LEN4);
}
Variable v = new Variable(ncfile, null, null, varname);
v.setDataType(type);
v.addAttribute(new Attribute("long_name", longName));
if (unit != null) {
v.addAttribute(new Attribute("units", unit));
}
if (type.equals(DataType.FLOAT)) {
v.addAttribute(new Attribute("missing_value", RMISS));
} else if (type.equals(DataType.INT)) {
v.addAttribute(new Attribute("missing_value", IMISS));
}
if ( !attrs.isEmpty()) {
for (Attribute attr : attrs) {
v.addAttribute(attr);
}
}
if ( !dims.isEmpty()) {
v.setDimensions(dims);
} else {
v.setDimensions((String) null);
}
return v;
}
/**
* Print the stack trace for a given line of code.
*
* @param msg message to print
* @param maxLines number of lines in the stack to print
*/
protected void printStack(String msg, int maxLines) {
String trace = getStackTrace();
if (msg != null) {
System.out.println(msg);
}
StringTokenizer tok = new StringTokenizer(trace, "\n");
int allcnt = 0;
int cnt = 0;
while (tok.hasMoreTokens()) {
String line = tok.nextToken();
allcnt++;
if (allcnt > 4) {
System.out.println(line);
cnt++;
if (cnt > maxLines) {
break;
}
}
}
}
/**
* Return the stack trace of this calling thread
*
* @return The stack trace
*/
protected String getStackTrace() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new IllegalArgumentException("").printStackTrace(
new PrintStream(baos));
return baos.toString();
}
}