/*
* 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.mcidas;
import ucar.grid.GridDefRecord;
import ucar.grid.GridParameter;
import ucar.grid.GridRecord;
import ucar.grid.GridTableLookup;
import ucar.ma2.*;
import ucar.nc2.*;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants.CF;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.iosp.AbstractIOServiceProvider;
import ucar.nc2.iosp.IOServiceProvider;
import ucar.nc2.iosp.grid.GridHorizCoordSys;
import ucar.nc2.util.CancelTask;
import ucar.unidata.io.RandomAccessFile;
import visad.Set;
import visad.VisADException;
import visad.data.BadFormException;
import visad.data.vis5d.Vis5DCoordinateSystem;
import visad.data.vis5d.Vis5DVerticalSystem;
import java.io.IOException;
import java.util.Date;
import java.util.Hashtable;
/**
* Vis5D grid file reader. Only support Vis5D grids, not the TOPO files.
*
* @author Unidata Development Team
*/
public class Vis5DIosp extends AbstractIOServiceProvider {
/** Vis5D file reader */
private V5DStruct v5dstruct;
/** file header */
private static final String V5D = "V5D";
/** from vis5d-4.3/src/v5d.h */
/** maximum number of varaiables */
private final static int MAXVARS = 200;
/** maximum number of times */
private final static int MAXTIMES = 400;
/** maximum number of rows */
private final static int MAXROWS = 400;
/** maximum number of columns */
private final static int MAXCOLUMNS = 400;
/** maximum number of levels */
private final static int MAXLEVELS = 400;
/** row variable name */
private final static String ROW = "row";
/** column variable name */
private final static String COLUMN = "col";
/** level variable name */
private final static String LEVEL = "lev";
/** time variable name */
private final static String TIME = "time";
/** latitude variable name */
private final static String LAT = "lat";
/** longitude variable name */
private final static String LON = "lon";
/** maximum number of projection arguments */
private final int MAXPROJARGS = MAXROWS + MAXCOLUMNS + 1;
/** maximum number of projection level arguments */
private final int MAXVERTARGS = MAXLEVELS + 1;
/** table of param name to units for well know params */
private static Hashtable<String, String> unitTable = null;
/** table of param name to var index */
private static Hashtable<Variable, Integer> varTable;
/** local copy of the raf */
private RandomAccessFile raf;
/** local copy of the ncfile */
private NetcdfFile ncfile;
/**
* Is this a valid file?
*
* @param raf RandomAccessFile to check
*
* @return true if a valid McIDAS AREA file
*
* @throws IOException problem reading file
*/
public boolean isValidFile(RandomAccessFile raf) throws IOException {
// quick test
raf.order(raf.BIG_ENDIAN);
raf.seek(0);
int n = V5D.length();
byte[] b = new byte[n];
raf.read(b);
String got = new String(b);
if (got.equals(V5D)) {
return true;
} else { // more rigorous test
V5DStruct vv = null;
try {
vv = V5DStruct.v5dOpenFile(raf);
} catch (BadFormException bfe) {
vv = null;
}
return vv != null;
}
}
/**
* Get the file type id
*
* @return the file type id
*/
public String getFileTypeId() {
return "Vis5D";
}
/**
* Get the file type description
*
* @return the file type description
*/
public String getFileTypeDescription() {
return "Vis5D grid file";
}
/**
* 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 {
long start = System.currentTimeMillis();
this.raf = raf;
this.ncfile = ncfile;
if (unitTable == null) {
initUnitTable();
}
if (v5dstruct == null) {
makeFile(raf, ncfile, cancelTask);
}
long end = System.currentTimeMillis() - start;
}
/**
* Make the netcdf file
*
* @param raf the RandomAccessFile
* @param ncfile the netCDF file handle
* @param cancelTask the cancel task
*
* @throws IOException problem reading the file
*/
private void makeFile(RandomAccessFile raf, NetcdfFile ncfile,
CancelTask cancelTask)
throws IOException {
ncfile.empty();
int[] sizes = new int[5];
int[] map_proj = new int[1];
String[] varnames = new String[MAXVARS];
String[] varunits = new String[MAXVARS];
int[] n_levels = new int[MAXVARS];
int[] vert_sys = new int[1];
float[] vertargs = new float[MAXVERTARGS];
double[] times = new double[MAXTIMES];
float[] projargs = new float[MAXPROJARGS];
V5DStruct vv = null;
try {
v5dstruct = V5DStruct.v5d_open(raf, sizes, n_levels, varnames,
varunits, map_proj, projargs,
vert_sys, vertargs, times);
} catch (BadFormException bfe) {
throw new IOException("Vis5DIosp.makeFile: bad file "
+ bfe.getMessage());
}
if (sizes[0] < 1) {
throw new IOException("Vis5DIosp.makeFile: bad file");
}
int nr = sizes[0];
int nc = sizes[1];
int nl = sizes[2];
int ntimes = sizes[3];
int nvars = sizes[4];
// System.out.println("nr: "+nr);
// System.out.println("nc: "+nc);
// System.out.println("nl: "+nl);
// System.out.println("ntimes: "+ntimes);
// System.out.println("nvars: "+nvars);
Dimension time = new Dimension(TIME, ntimes, true);
Dimension row = new Dimension(ROW, nr, true);
Dimension col = new Dimension(COLUMN, nc, true);
ncfile.addDimension(null, time);
ncfile.addDimension(null, row);
ncfile.addDimension(null, col);
// time
Variable timeVar = new Variable(ncfile, null, null, TIME);
timeVar.setDataType(DataType.DOUBLE);
timeVar.setDimensions(TIME);
timeVar.addAttribute(
new Attribute("units", "seconds since 1900-01-01 00:00:00"));
timeVar.addAttribute(new Attribute("long_name", TIME));
timeVar.addAttribute(new Attribute(_Coordinate.AxisType,
AxisType.Time.toString()));
Array varArray = new ArrayDouble.D1(ntimes);
for (int i = 0; i < ntimes; i++) {
((ArrayDouble.D1) varArray).set(i, times[i]);
}
timeVar.setCachedData(varArray, false);
ncfile.addVariable(null, timeVar);
// rows and columns
Variable rowVar = new Variable(ncfile, null, null, ROW);
rowVar.setDataType(DataType.INT);
rowVar.setDimensions(ROW);
varArray = new ArrayInt.D1(nr);
for (int i = 0; i < nr; i++) {
((ArrayInt.D1) varArray).set(i, i);
}
rowVar.setCachedData(varArray, false);
ncfile.addVariable(null, rowVar);
Variable colVar = new Variable(ncfile, null, null, COLUMN);
colVar.setDataType(DataType.INT);
colVar.setDimensions(COLUMN);
varArray = new ArrayInt.D1(nc);
for (int i = 0; i < nc; i++) {
((ArrayInt.D1) varArray).set(i, i);
}
colVar.setCachedData(varArray, false);
ncfile.addVariable(null, colVar);
// sanity check on levels
Hashtable<Integer, Object> var_table = new Hashtable<Integer,
Object>();
boolean have3D = false;
for (int i = 0; i < nvars; i++) {
int nlevs = n_levels[i];
if ( !have3D && (nlevs > 1)) {
have3D = true;
}
var_table.put(new Integer(nlevs), new Object());
}
int n_var_groups = var_table.size();
if (n_var_groups > 2) {
throw new IOException(
"Vis5DIosp.makeFile: more than two variable groups by n_levels");
} else if (n_var_groups == 0) {
throw new IOException(
"Vis5DIosp.makeFile: number of variable groups == 0");
}
Variable vert = null;
if (have3D) {
Dimension lev = new Dimension(LEVEL, nl, true);
ncfile.addDimension(null, lev);
vert = makeVerticalVariable(vert_sys[0], nl, vertargs);
if (vert != null) {
ncfile.addVariable(null, vert);
}
}
varTable = new Hashtable<Variable, Integer>();
String dim3D = TIME + " " + LEVEL + " " + COLUMN + " " + ROW;
String dim2D = TIME + " " + COLUMN + " " + ROW;
//String coords3D = TIME + " " + vert.getName() + " " + LAT + " " + LON;
String coords3D = "unknown";
if (vert != null) {
coords3D = TIME + " Height " + LAT + " " + LON;
}
String coords2D = TIME + " " + LAT + " " + LON;
for (int i = 0; i < nvars; i++) {
Variable v = new Variable(ncfile, null, null, varnames[i]);
if (n_levels[i] > 1) {
v.setDimensions(dim3D);
v.addAttribute(new Attribute("coordinates", coords3D));
} else {
v.setDimensions(dim2D);
v.addAttribute(new Attribute("coordinates", coords2D));
}
v.setDataType(DataType.FLOAT);
String units = varunits[i].trim();
if (units.equals("")) { // see if its in the unitTable
String key = varnames[i].trim().toLowerCase();
units = unitTable.get(key);
}
if (units != null) {
v.addAttribute(new Attribute(CF.UNITS, units));
}
// TODO: do two vars with the same name have different values?
// check agaist duplicat variable names
if (varTable.get(v) == null) {
varTable.put(v, new Integer(i));
ncfile.addVariable(null, v);
}
}
double[][] proj_args = Set.floatToDouble(new float[][] {
projargs
});
addLatLonVariables(map_proj[0], proj_args[0], nr, nc);
Vis5DGridDefRecord gridDef = new Vis5DGridDefRecord(map_proj[0],
proj_args[0], nr, nc);
ncfile.addAttribute(null, new Attribute("Conventions", "CF-1.0"));
ncfile.finish();
}
/**
* Read the data for the variable
* @param v2 Variable to read
* @param section section infomation
* @return Array of data
*
* @throws IOException problem reading from file
* @throws InvalidRangeException invalid Range
*/
public Array readData(Variable v2, Section section)
throws IOException, InvalidRangeException {
long startTime = System.currentTimeMillis();
Integer varIdx = varTable.get(v2);
if (varIdx == null) {
throw new IOException("unable to find variable index");
}
int count = 0;
int[] shape = v2.getShape();
boolean haveZ = shape.length == 4;
int nt = shape[count++];
int nz = haveZ
? shape[count++]
: 1;
int ny = shape[count++];
int nx = shape[count];
count = 0;
Array dataArray = Array.factory(DataType.FLOAT, section.getShape());
Range timeRange = section.getRange(count++);
Range zRange = haveZ
? section.getRange(count++)
: null;
Range yRange = section.getRange(count++);
Range xRange = section.getRange(count);
int grid_size = nx * ny * nz;
IndexIterator ii = dataArray.getIndexIterator();
// loop over time
for (int timeIdx = timeRange.first(); timeIdx <= timeRange.last();
timeIdx += timeRange.stride()) {
float[] data = new float[grid_size];
float[] ranges = new float[2];
try {
v5dstruct.v5d_read(timeIdx, varIdx.intValue(), ranges, data);
} catch (BadFormException bfe) {
throw new IOException("Vis5DIosp.readData: "
+ bfe.getMessage());
}
if ((ranges[0] >= 0.99E30) && (ranges[1] <= -0.99E30)) {
//range_sets[j] = new Linear1DSet(0.0, 1.0, 255);
} else if (ranges[0] > ranges[1]) {
throw new IOException("Vis5DIosp.readData: bad read "
+ v2.getFullName());
}
// invert the rows
float[] tmp_data = new float[grid_size];
if (zRange == null) {
int cnt = 0;
for (int mm = 0; mm < ny; mm++) {
int start = (mm + 1) * nx - 1;
for (int nn = 0; nn < nx; nn++) {
tmp_data[cnt++] = data[start--];
}
}
} else {
int cnt = 0;
for (int ll = 0; ll < nz; ll++) {
for (int mm = 0; mm < ny; mm++) {
int start = ((mm + 1) * nx - 1) + nx * ny * ll;
for (int nn = 0; nn < nx; nn++) {
tmp_data[cnt++] = data[start--];
}
}
}
}
data = tmp_data;
if (zRange != null) {
for (int z = zRange.first(); z <= zRange.last();
z += zRange.stride()) {
for (int y = yRange.first(); y <= yRange.last();
y += yRange.stride()) {
for (int x = xRange.first(); x <= xRange.last();
x += xRange.stride()) {
int index = z * nx * ny + y * nx + x;
ii.setFloatNext(data[index]);
}
}
}
} else {
for (int y = yRange.first(); y <= yRange.last();
y += yRange.stride()) {
for (int x = xRange.first(); x <= xRange.last();
x += xRange.stride()) {
int index = y * nx + x;
ii.setFloatNext(data[index]);
}
}
}
}
long end = System.currentTimeMillis() - startTime;
return dataArray;
}
/**
* Close this IOSP
*
* @throws IOException problem closing file
*/
public void close() throws IOException {
if (v5dstruct != null) {
v5dstruct = null;
}
}
/**
* Test this.
*
* @param args [0] input file name [0] output file name
*
* @throws IOException problem reading the file
*/
public static void main(String[] args) throws IOException {
IOServiceProvider areaiosp = new Vis5DIosp();
RandomAccessFile rf = new RandomAccessFile(args[0], "r", 2048);
NetcdfFile ncfile = new MakeNetcdfFile(areaiosp, rf, args[0], null);
System.out.println(ncfile);
if (args.length > 1) {
ucar.nc2.FileWriter.writeToFile(ncfile, args[1]);
}
}
/**
* TODO: generalize this
* static class for testing
*/
protected static class MakeNetcdfFile extends NetcdfFile {
MakeNetcdfFile(IOServiceProvider spi, RandomAccessFile raf,
String location, CancelTask cancelTask)
throws IOException {
super(spi, raf, location, cancelTask);
}
}
/**
* Initialize the unit table. This is used if there are no
* units in the file.
*/
private static void initUnitTable() {
unitTable = new Hashtable<String, String>();
// temperatures
unitTable.put("t", "K");
unitTable.put("td", "K");
unitTable.put("thte", "K");
// winds
unitTable.put("u", "m/s");
unitTable.put("v", "m/s");
unitTable.put("w", "m/s");
// pressure
unitTable.put("p", "hPa");
unitTable.put("mmsl", "hPa");
// moisture
unitTable.put("rh", "%");
// misc
unitTable.put("rhfz", "%");
unitTable.put("zagl", "m");
}
/**
* Create a vertical dimension variable based on the info. Based on
* visad.data.vis5d.Vis5DVerticalSystem.
*
* @param vert_sys the vertical system id
* @param n_levels the number of levels
* @param vert_args the vertical system arguments
*
* @return the vertical dimesion variable
*
* @throws IOException problem reading the file or creating the data
*/
private Variable makeVerticalVariable(int vert_sys, int n_levels,
float[] vert_args)
throws IOException {
String vert_unit = null;
String vert_type;
ArrayFloat.D1 data = new ArrayFloat.D1(n_levels);
AxisType axisType = null;
switch (vert_sys) {
case (0) :
vert_unit = null;
vert_type = "height";
break;
case (1) :
case (2) :
vert_unit = "km";
vert_type = "altitude";
axisType = AxisType.Height;
break;
case (3) :
vert_unit = "mbar";
vert_type = "pressure";
axisType = AxisType.Pressure;
break;
default :
throw new IOException("vert_sys unknown");
}
Variable vertVar = new Variable(ncfile, null, null, vert_type);
vertVar.setDimensions(LEVEL);
vertVar.setDataType(DataType.FLOAT);
if (vert_unit != null) {
vertVar.addAttribute(new Attribute(CF.UNITS, vert_unit));
}
if (axisType != null) {
vertVar.addAttribute(new Attribute(_Coordinate.AxisType,
axisType.toString()));
}
switch (vert_sys) {
case (0) :
case (1) :
for (int i = 0; i < n_levels; i++) {
data.set(i, vert_args[0] + vert_args[1] * i);
}
break;
case (2) : // Altitude in km - non-linear
for (int i = 0; i < n_levels; i++) {
data.set(i, vert_args[i]);
}
break;
case (3) : // heights of pressure surfaces in km - non-linear
try {
Vis5DVerticalSystem.Vis5DVerticalCoordinateSystem vert_cs =
new Vis5DVerticalSystem.Vis5DVerticalCoordinateSystem();
float[][] pressures = new float[1][n_levels];
System.arraycopy(vert_args, 0, pressures[0], 0, n_levels);
for (int i = 0; i < n_levels; i++) {
pressures[0][i] *= 1000; // km->m
}
pressures = vert_cs.fromReference(pressures); // convert to pressures
for (int i = 0; i < n_levels; i++) {
data.set(i, pressures[0][i]);
}
} catch (VisADException ve) {
throw new IOException("unable to make vertical system");
}
break;
default :
throw new IOException("vert_sys unknown");
}
vertVar.setCachedData(data, false);
return vertVar;
}
/**
* Add lat/lon variables to the file
*
* @param map_proj the map projection identifier
* @param proj_args the projection args
* @param nr number of rows
* @param nc number of columns
*
* @throws IOException Problem making the projection
*/
private void addLatLonVariables(int map_proj, double[] proj_args, int nr,
int nc)
throws IOException {
//Vis5DGridDefRecord.printProjArgs(map_proj, proj_args);
Vis5DGridDefRecord vgd = new Vis5DGridDefRecord(map_proj, proj_args,
nr, nc);
GridHorizCoordSys ghc = new GridHorizCoordSys(vgd, new Vis5DLookup(),
null);
Vis5DCoordinateSystem coord_sys;
try {
coord_sys = new Vis5DCoordinateSystem(map_proj, proj_args, nr,
nc);
Variable lat = new Variable(ncfile, null, null, LAT);
lat.setDimensions(COLUMN + " " + ROW);
lat.setDataType(DataType.DOUBLE);
lat.addAttribute(new Attribute("long_name", "latitude"));
lat.addAttribute(new Attribute(CF.UNITS, "degrees_north"));
lat.addAttribute(new Attribute(CF.STANDARD_NAME, "latitude"));
lat.addAttribute(new Attribute(_Coordinate.AxisType,
AxisType.Lat.toString()));
ncfile.addVariable(null, lat);
Variable lon = new Variable(ncfile, null, null, LON);
lon.setDimensions(COLUMN + " " + ROW);
lon.setDataType(DataType.DOUBLE);
lon.addAttribute(new Attribute(CF.UNITS, "degrees_east"));
lon.addAttribute(new Attribute("long_name", "longitude"));
lon.addAttribute(new Attribute(CF.STANDARD_NAME, "longitude"));
lon.addAttribute(new Attribute(_Coordinate.AxisType,
AxisType.Lon.toString()));
ncfile.addVariable(null, lon);
int[] shape = new int[] { nc, nr };
Array latArray = Array.factory(DataType.DOUBLE, shape);
Array lonArray = Array.factory(DataType.DOUBLE, shape);
double[][] rowcol = new double[2][nr * nc];
for (int x = 0; x < nc; x++) {
for (int y = 0; y < nr; y++) {
int index = x * nr + y;
rowcol[0][index] = y;
rowcol[1][index] = x;
}
}
double[][] latlon = coord_sys.toReference(rowcol);
Index latIndex = latArray.getIndex();
Index lonIndex = lonArray.getIndex();
/*
for (int y = 0; y < nr; y++) {
for (int x = 0; x < nc; x++) {
int index = y * nc + x;
*/
for (int x = 0; x < nc; x++) {
for (int y = 0; y < nr; y++) {
int index = x * nr + y;
/*
latArray.setDouble(latIndex.set(x, y), latlon[0][index]);
lonArray.setDouble(lonIndex.set(x, y), latlon[1][index]);
*/
latArray.setDouble(index, latlon[0][index]);
lonArray.setDouble(index, latlon[1][index]);
}
}
lat.setCachedData(latArray, false);
lon.setCachedData(lonArray, false);
} catch (VisADException ve) {
throw new IOException("Vis5DIosp.addLatLon: " + ve.getMessage());
}
}
/**
* Get all the information about a Vis5D file
*/
public class Vis5DLookup implements GridTableLookup {
/**
*
* Gets a representative grid for this lookup
*/
public Vis5DLookup() {}
/**
* .
* @param gds
* @return ShapeName.
*/
public String getShapeName(GridDefRecord gds) {
return "Spherical";
}
/**
* gets the grid type.
* @param gds
* @return GridName
*/
public final String getGridName(GridDefRecord gds) {
return gds.toString();
}
/**
* gets parameter table, then grib1 parameter based on number.
* @param gr GridRecord
* @return Parameter
*/
public final GridParameter getParameter(GridRecord gr) {
// not needed for this implementation
return null;
}
/**
* gets the DisciplineName.
* @param gr
* @return DisciplineName
*/
public final String getDisciplineName(GridRecord gr) {
// all disciplines are the same in Vis5D
return "Meteorological Products";
}
/**
* gets the CategoryName.
* @param gr
* @return CategoryName
*/
public final String getCategoryName(GridRecord gr) {
// no categories in Vis5D
return "Meteorological Parameters";
}
/**
* gets the LevelName.
* @param gr
* @return LevelName
*/
public final String getLevelName(GridRecord gr) {
// not needed for this implementation
return null;
}
/**
* gets the LevelDescription.
* @param gr
* @return LevelDescription
*/
public final String getLevelDescription(GridRecord gr) {
// not needed for this implementation
return null;
}
/**
* gets the LevelUnit.
* @param gr
* @return LevelUnit
*/
public final String getLevelUnit(GridRecord gr) {
// not needed for this implementation
return null;
}
public final String getTimeRangeUnitName( int tunit) {
return "second";
}
/**
* gets the BaseTime Forecastime.
* @return BaseTime
*/
public final java.util.Date getFirstBaseTime() {
return new Date();
}
/**
* is this a LatLon grid.
* @param gds
* @return isLatLon
*/
public final boolean isLatLon(GridDefRecord gds) {
return getProjectionName(gds).equals("GENERIC")
|| getProjectionName(gds).equals("LINEAR")
|| getProjectionName(gds).equals("CYLINDRICAL")
|| getProjectionName(gds).equals("SPHERICAL");
}
/**
* gets the ProjectionType.
* @param gds
* @return ProjectionType
*/
public final int getProjectionType(GridDefRecord gds) {
String name = getProjectionName(gds).trim();
if (name.equals("LAMBERT")) {
return LambertConformal;
} else if (name.equals("STEREO")) {
return PolarStereographic;
} else {
return -1;
}
}
/**
* is this a VerticalCoordinate.
* @param gr
* @return isVerticalCoordinate
*/
public final boolean isVerticalCoordinate(GridRecord gr) {
// not needed for this implementation
return false;
}
/**
* is this a PositiveUp VerticalCoordinate.
* @param gr
* @return isPositiveUp
*/
public final boolean isPositiveUp(GridRecord gr) {
// not needed for this implementation
return false;
}
/**
* gets the MissingValue.
* @return MissingValue
*/
public final float getFirstMissingValue() {
return -9999;
}
/**
* Is this a layer?
*
* @param gr record to check
*
* @return true if a layer
*/
public boolean isLayer(GridRecord gr) {
return false;
}
/**
* Get the projection name
*
* @param gds the projection name
*
* @return the name or null if not set
*/
private String getProjectionName(GridDefRecord gds) {
return gds.getParam(gds.PROJ);
}
// CF Conventions Global Attributes
/**
* gets the CF title.
*
* @return title
*/
public final String getTitle() {
return "GRID data";
}
/**
* Institution for CF conventions
*
* @return Institution
*/
public String getInstitution() {
return null;
}
/**
* gets the Source, Generating Process or Model.
*
* @return source
*/
public final String getSource() {
return null;
}
/**
* comment for CF conventions.
*
* @return comment
*/
public final String getComment() {
return null;
}
/**
* Get the grid type for labelling
*
* @return the grid type
*/
public String getGridType() {
return "Vis5D";
}
}
}