ucar.nc2.iosp.mcidas.V5DStruct Maven / Gradle / Ivy
Show all versions of netcdf Show documentation
//
// V5DStruct.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2009 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
//package visad.data.vis5d;
package ucar.nc2.iosp.mcidas;
import visad.data.BadFormException;
// original V5DStruct uses ucar.unidata.netcdf.RandomAccessFile
import ucar.unidata.io.RandomAccessFile;
import java.io.IOException;
import java.net.URL;
/** An object representing the structure of a .v5d file. */
public class V5DStruct {
/** Amount of physical RAM in megabytes.
Vis5D normally uses a bounded amount of memory to avoid swapping.
When the limit is reached, the least-recently-viewed graphics will
be deallocated. If MBS is set to 0, however, vis5d will use ordinary
malloc/free and not deallocate graphics (ok for systems with a lot
of memory (>=128MB)).
*/
private static final int MBS = 32;
/** Default topography file */
private static final String TOPOFILE = "EARTH.TOPO";
/** Default world map lines file */
private static final String WORLDFILE = "OUTLSUPW";
/** Default USA map lines file */
private static final String USAFILE = "OUTLUSAM";
/** Default filename of Tcl startup commands */
private static final String TCL_STARTUP_FILE = "vis5d.tcl";
/** Default directory to search for user functions */
private static final String FUNCTION_PATH = "userfuncs";
/** Default animation rate in milliseconds */
private static final int ANIMRATE = 100;
/** Default scale value for logarithmic vertical coordinate system */
private static final double DEFAULT_LOG_SCALE = 1012.5;
/** Default exponent value for logarithmic vertical coordinate system */
private static final double DEFAULT_LOG_EXP = -7.2;
// ******************************************************************** //
// ******************************************************************** //
// ** USERS: DON'T CHANGE THE FOLLOWING CONSTANTS ** //
// ******************************************************************** //
// ******************************************************************** //
/** Define BIG_GFX to allow larger isosurfaces, contour slices, etc., if
there's enough memory.
*/
private static final boolean BIG_GFX = true;
/** Shared by code above and below API */
private static final int MAX_LABEL = 1000;
/** Shared by code above and below API */
private static final int MAX_FUNCS = 100;
/** A numeric version number which we can test for in utility programs which
use the v5d functions. If V5D_VERSION is not defined, then its value
is considered to be zero.
*/
private static final int V5D_VERSION = 42;
/** Represents a missing value */
private static final float MISSING = Float.NaN;
/** Tests whether a given value is missing */
private static boolean IS_MISSING(float x) {
return Float.isNaN(x) || x >= 1.0e30;
}
/** Limit on 5-D grid variables */
private static final int MAXVARS = 200;
/** Limit on 5-D grid times */
private static final int MAXTIMES = 400;
/** Limit on 5-D grid rows */
private static final int MAXROWS = 400;
/** Limit on 5-D grid columns */
private static final int MAXCOLUMNS = 400;
/** Limit on 5-D grid levels */
private static final int MAXLEVELS = 400;
// ********************************************************************** //
// ** ** //
// ** Definition of v5d struct and related information. ** //
// ** ** //
// ********************************************************************** //
private static final int MAXPROJARGS = (MAXROWS+MAXCOLUMNS+1);
private static final int MAXVERTARGS = (MAXLEVELS+1);
/** File version. This should be updated when the file version changes. */
private static final String FILE_VERSION = "4.3";
// TODO: find optimal value of default buffer size
private static final int DEFAULT_FILE_BUFFER = 204800;
private static final int DEFAULT_HTTP_BUFFER = 204800;
/*
* New grid file format for VIS-5D:
*
* The header is a list of tagged items. Each item has 3 parts:
* 1. A tag which is a 4-byte integer identifying the type of item.
* 2. A 4-byte integer indicating how many bytes of data follow.
* 3. The binary data.
*
* If we need to add new information to a file header we just create a
* new tag and add the code to read/write the information.
*
* If we're reading a header and find an unknown tag, we can use the
* length field to skip ahead to the next tag. Therefore, the file
* format is forward (and backward) compatible.
*
* Grid data is stored as either:
* 1-byte unsigned integers (255=missing)
* 2-byte unsigned integers (65535=missing)
* 4-byte IEEE floats (>1.0e30 = missing)
*
* All numeric values are stored in big endian order. All floating point
* values are in IEEE format.
*/
/*
* Currently defined tags:
* Note: the notation a[i] doesn't mean a is an array of i elements,
* rather it just refers to the ith element of a[].
*
* Tags marked as PHASED OUT should be readable but are no longer written.
* Old tag numbers can't be reused!
*
*/
/** hex encoding of "V5D\n" */
public static final int TAG_ID = 0x5635440a;
// general stuff 1000+
/** char*10 FileVersion */
public static final int TAG_VERSION = 1000;
/** int*4 NumTimes */
public static final int TAG_NUMTIMES = 1001;
/** int*4 NumVars */
public static final int TAG_NUMVARS = 1002;
/** int*4 var; char*10 VarName[var] */
public static final int TAG_VARNAME = 1003;
/** int*4 Nr */
public static final int TAG_NR = 1004;
/** int*4 Nc */
public static final int TAG_NC = 1005;
/** int*4 Nl (Nl for all vars) */
public static final int TAG_NL = 1006;
/** int*4 var; int*4 Nl[var] */
public static final int TAG_NL_VAR = 1007;
/** int*4 var; int*4 LowLev[var] */
public static final int TAG_LOWLEV_VAR = 1008;
/** int*4 t; int*4 TimeStamp[t] */
public static final int TAG_TIME = 1010;
/** int*4 t; int*4 DateStamp[t] */
public static final int TAG_DATE = 1011;
/** int*4 var; real*4 MinVal[var] */
public static final int TAG_MINVAL = 1012;
/** int*4 var; real*4 MaxVal[var] */
public static final int TAG_MAXVAL = 1013;
/** int*4 CompressMode; (#bytes/grid) */
public static final int TAG_COMPRESS = 1014;
/** int *4 var; char*20 Units[var] */
public static final int TAG_UNITS = 1015;
// vertical coordinate system 2000+
/** int*4 VerticalSystem */
public static final int TAG_VERTICAL_SYSTEM = 2000;
/** int*4 n; real*4 VertArgs[0..n-1] */
public static final int TAG_VERT_ARGS = 2100;
/** real*4 BottomBound (PHASED OUT) */
public static final int TAG_BOTTOMBOUND = 2001;
/** real*4 LevInc (PHASED OUT) */
public static final int TAG_LEVINC = 2002;
/** int*4 l; real*4 Height[l] (PHASED OUT) */
public static final int TAG_HEIGHT = 2003;
// projection 3000+
/** int*4 projection.
0 = generic linear
1 = cylindrical equidistant
2 = Lambert conformal/Polar Stereo
3 = rotated equidistant
*/
public static final int TAG_PROJECTION = 3000;
/** int*4 n; real*4 ProjArgs[0..n-1] */
public static final int TAG_PROJ_ARGS = 3100;
/** real*4 NorthBound (PHASED OUT) */
public static final int TAG_NORTHBOUND = 3001;
/** real*4 WestBound (PHASED OUT) */
public static final int TAG_WESTBOUND = 3002;
/** real*4 RowInc (PHASED OUT) */
public static final int TAG_ROWINC = 3003;
/** real*4 ColInc (PHASED OUT) */
public static final int TAG_COLINC = 3004;
/** real*4 Lat1 (PHASED OUT) */
public static final int TAG_LAT1 = 3005;
/** real*4 Lat2 (PHASED OUT) */
public static final int TAG_LAT2 = 3006;
/** real*4 PoleRow (PHASED OUT) */
public static final int TAG_POLE_ROW = 3007;
/** real*4 PoleCol (PHASED OUT) */
public static final int TAG_POLE_COL = 3008;
/** real*4 CentralLon (PHASED OUT) */
public static final int TAG_CENTLON = 3009;
/** real*4 CentralLat (PHASED OUT) */
public static final int TAG_CENTLAT = 3010;
/** real*4 CentralRow (PHASED OUT) */
public static final int TAG_CENTROW = 3011;
/** real*4 CentralCol (PHASED OUT) */
public static final int TAG_CENTCOL = 3012;
/** real*4 Rotation (PHASED OUT) */
public static final int TAG_ROTATION = 3013;
public static final int TAG_END = 9999;
// ******************************* //
// *** Start of main v5dstruct *** //
// ******************************* //
// PUBLIC (user can freely read, sometimes write, these fields)
/** Number of time steps */
public int NumTimes;
/** Number of variables */
public int NumVars;
/** Number of rows */
public int Nr;
/** Number of columns */
public int Nc;
/** Number of levels per variable */
public int[] Nl = new int[MAXVARS];
/** Lowest level per variable */
public int[] LowLev = new int[MAXVARS];
/** 9-character variable names */
public char[][] VarName = new char[MAXVARS][10];
/** 19-character units for variables */
public char[][] Units = new char[MAXVARS][20];
/** Time in HHMMSS format */
public int[] TimeStamp = new int[MAXTIMES];
/** Date in YYDDD format */
public int[] DateStamp = new int[MAXTIMES];
/** Minimum variable data values */
public float[] MinVal = new float[MAXVARS];
/** Maximum variable data values */
public float[] MaxVal = new float[MAXVARS];
// This info is used for external function computation
/** McIDAS file number in 1..9999 */
public short[][] McFile = new short[MAXTIMES][MAXVARS];
/** McIDAS grid number in 1..? */
public short[][] McGrid = new short[MAXTIMES][MAXVARS];
/** Which vertical coordinate system */
public int VerticalSystem;
/** Vertical Coordinate System arguments.
IF VerticalSystem==0 THEN
-- Linear scale, equally-spaced levels in generic units
VertArgs[0] = Height of bottom-most grid level in generic units
VertArgs[1] = Increment between levels in generic units
ELSE IF VerticalSystem==1 THEN
-- Linear scale, equally-spaced levels in km
VertArgs[0] = Height of bottom grid level in km
VertArgs[1] = Increment between levels in km
ELSE IF VerticalSystem==2 THEN
-- Linear scale, Unequally spaced levels in km
VertArgs[0] = Height of grid level 0 (bottom) in km
... ...
VertArgs[n] = Height of grid level n in km
ELSE IF VerticalSystem==3 THEN
-- Linear scale, Unequally spaced levels in mb
VertArgs[0] = Pressure of grid level 0 (bottom) in mb
... ...
VertArgs[n] = Pressure of grid level n in mb
ENDIF
*/
public float[] VertArgs = new float[MAXVERTARGS];
/** Which map projection */
public int Projection;
/** Map projection arguments.
IF Projection==0 THEN
-- Rectilinear grid, generic units
ProjArgs[0] = North bound, Y coordinate of grid row 0
ProjArgs[1] = West bound, X coordiante of grid column 0
ProjArgs[2] = Increment between rows
ProjArgs[3] = Increment between colums
NOTES: X coordinates increase to the right, Y increase upward.
NOTES: Coordinate system is right-handed.
ELSE IF Projection==1 THEN
-- Cylindrical equidistant (Old VIS-5D)
-- Rectilinear grid in lat/lon
ProjArgs[0] = Latitude of grid row 0, north bound, in degrees
ProjArgs[1] = Longitude of grid column 0, west bound, in deg.
ProjArgs[2] = Increment between rows in degrees
ProjArgs[3] = Increment between rows in degrees
NOTES: Coordinates (degrees) increase to the left and upward.
ELSE IF Projection==2 THEN
-- Lambert conformal
ProjArgs[0] = Standared Latitude 1 of conic projection
ProjArgs[1] = Standared Latitude 2 of conic projection
ProjArgs[2] = Row of North/South pole
ProjArgs[3] = Column of North/South pole
ProjArgs[4] = Longitude which is parallel to columns
ProjArgs[5] = Increment between grid columns in km
ELSE IF Projection==3 THEN
-- Polar Stereographic
ProjArgs[0] = Latitude of center of projection
ProjArgs[1] = Longitude of center of projection
ProjArgs[2] = Grid row of center of projection
ProjArgs[3] = Grid column of center of projection
ProjArgs[4] = Increment between grid columns at center in km
ELSE IF Projection==4 THEN
-- Rotated
ProjArgs[0] = Latitude on rotated globe of grid row 0
ProjArgs[1] = Longitude on rotated globe of grid column 0
ProjArgs[2] = Degrees of latitude on rotated globe between
grid rows
ProjArgs[3] = Degrees of longitude on rotated globe between
grid columns
ProjArgs[4] = Earth latitude of (0, 0) on rotated globe
ProjArgs[5] = Earth longitude of (0, 0) on rotated globe
ProjArgs[6] = Clockwise rotation of rotated globe in degrees
ENDIF
*/
public float[] ProjArgs = new float[MAXPROJARGS];
/** 1, 2 or 4 = # bytes per grid point */
public int CompressMode;
/** 9-character version number */
public String FileVersion;
// PRIVATE (not to be touched by user code)
/** COMP5D file version or 0 if .v5d */
private int FileFormat;
/** Java file descriptor */
private RandomAccessFile FileDesc;
/** 'r' = read, 'w' = write */
char Mode;
/** current position of file pointer */
int CurPos;
/** position of first grid in file */
int FirstGridPos;
/** size of each grid */
int[] GridSize = new int[MAXVARS];
/** sum of GridSize[0..NumVars-1] */
int SumGridSizes;
// ************************* //
// *** GATEWAY FUNCTIONS *** //
// ************************* //
/** Open a Vis5D file */
public
static
//V5DStruct v5d_open( byte[] name, int name_length, int[] sizes,
V5DStruct v5d_open( RandomAccessFile raf, int[] sizes,
int[] n_levels,
String[] var_names, String[] var_units,
int[] map_proj, float[] projargs,
int[] vert_sys, float[] vert_args, double[] times)
throws IOException, BadFormException
{
int i, j, k, k2, m, m2;
int day, time, first_day, first_time;
// char[] filename = new char[200];
byte[] varnames = new byte[10*MAXVARS];
byte[] varunits = new byte[20*MAXVARS];
// open file
// Modified 01-Feb-2005 DRM: caused problems on Mac-OSX
//for (i=0; i maxNl) maxNl = v.Nl[i];
/*----if (v.Nl[i] != maxNl) sizes[0] = -1; */
}
sizes[2] = maxNl;
for (i = 0; i < v.NumVars; i++) {
n_levels[i] = v.Nl[i];
}
vert_sys[0] = v.VerticalSystem;
for ( int kk = 0; kk < maxNl; kk++) {
vert_args[kk] = v.VertArgs[kk];
}
// compute times
first_day = v5dYYDDDtoDays(v.DateStamp[0]);
first_time = v5dHHMMSStoSeconds(v.TimeStamp[0]);
for (i=0; i= 0 ? (int) b : (int) b + 256);
return i;
}
/** Convert two signed bytes to an unsigned short, and return it in an int */
public static int getUnsignedShort(byte b1, byte b2) {
int i1 = getUnsignedByte(b1);
int i2 = getUnsignedByte(b2);
return 256 * i1 + i2;
}
/** Convert four signed bytes to an unsigned short, and return it in an int */
public static int getUnsignedInt(byte b1, byte b2, byte b3, byte b4) {
int i1 = getUnsignedByte(b1);
int i2 = getUnsignedByte(b2);
int i3 = getUnsignedByte(b3);
int i4 = getUnsignedByte(b4);
return 16777216*i1 + 65536*i2 + 256*i3 + i4;
}
private static float pressure_to_height(float pressure) {
return (float) (DEFAULT_LOG_EXP *
Math.log((double) pressure / DEFAULT_LOG_SCALE));
}
private static float height_to_pressure(float height) {
return (float) (DEFAULT_LOG_SCALE *
Math.exp((double) height / DEFAULT_LOG_EXP));
}
/** Copy up to maxlen characters from src to dst stopping upon whitespace
in src. Terminate dst with null character.
@return length of dst
*/
private static int copy_string2(char[] dst, char[] src, int maxlen) {
int i;
for (i=0;i=0; i--) {
if (dst[i] == ' ' || i == maxlen - 1) dst[i] = 0;
else break;
}
return new String(dst).length();
}
/** Copy up to maxlen characters from src to dst stopping upon whitespace
in src. Terminate dst with null character.
@return length of dst
*/
private static int copy_string(char[] dst, char[] src, int maxlen) {
int i;
for (i=0; i= 1900)
iy -= 1900;
else if (iy < 50)
// WLH 31 July 96 << 31 Dec 99
iy += 100;
// Updated from Vis5D+ (sub 1 since they do days from 12/31/1899)
//idays = 365 * iy + (iy - 1) / 4 + id;
idays = (365*iy + (iy-1)/4 - (iy-1)/100 + (iy+299)/400 + id) - 1;
return idays;
}
/** Convert a time from HHMMSS format to seconds since midnight. */
private static int v5dHHMMSStoSeconds(int hhmmss) {
int h, m, s;
h = hhmmss / 10000;
m = (hhmmss / 100) % 100;
s = hhmmss % 100;
return s + m * 60 + h * 60 * 60;
}
/** Convert a day since Jan 1, 1900 to YYDDD format. */
private static int v5dDaysToYYDDD(int days) {
int iy, id, iyyddd;
iy = (4 * days) / 1461;
id = days - (365 * iy + (iy - 1) / 4);
// WLH 31 July 96 << 31 Dec 99
// iy = iy + 1900; is the right way to fix this, but requires
// changing all places where dates are printed - procrastinate
if (iy > 99) iy = iy - 100;
iyyddd = iy * 1000 + id;
return iyyddd;
}
/** Convert a time in seconds since midnight to HHMMSS format. */
private static int v5dSecondsToHHMMSS(int seconds) {
int hh, mm, ss;
hh = seconds / (60 * 60);
mm = (seconds / 60) % 60;
ss = seconds % 60;
return hh * 10000 + mm * 100 + ss;
}
/** Open a v5d file for reading.
@return null if error, else a pointer to a new V5DStruct
private static V5DStruct v5dOpenFile(String filename)
throws IOException, BadFormException {
RandomAccessFile fd =
(filename.toLowerCase().startsWith("http"))
? new HTTPRandomAccessFile(new URL(filename), DEFAULT_HTTP_BUFFER )
: new RandomAccessFile(filename, "r", DEFAULT_FILE_BUFFER);
if (fd == null) {
// error
return null;
}
V5DStruct v = new V5DStruct();
v.FileDesc = fd;
v.Mode = 'r';
return (v.read_v5d_header() ? v : null);
}
*/
/** Open a v5d file for reading.
@return null if error, else a pointer to a new V5DStruct
*/
public static V5DStruct v5dOpenFile(RandomAccessFile fd)
throws IOException, BadFormException {
if (fd == null) {
// error
System.out.println("null file");
return null;
}
V5DStruct v = new V5DStruct();
v.FileDesc = fd;
v.Mode = 'r';
return (v.read_v5d_header() ? v : null);
}
/** Compute the ga and gb (de)compression values for a grid.
@param nr number of rows of grid
@param nc number of columns of grid
@param nl number of levels of grid
@param data the grid data
@param ga array to store results
@param gb array to store results
@param minval one-element float array for storing min value
@param maxval one-element float array for storing max value
@param compressmode 1, 2 or 4 bytes per grid point
*/
private static void compute_ga_gb(int nr, int nc, int nl, float[] data,
int compressmode, float[] ga, float[] gb, float[] minval, float[] maxval)
throws BadFormException{
if (SIMPLE_COMPRESSION) {
// compute ga, gb values for whole grid
int i, lev, num;
boolean allmissing;
float min, max, a, b;
min = 1.0e30f;
max = -1.0e30f;
num = nr * nc * nl;
allmissing = true;
for (i=0; i max) max = data[i];
allmissing = false;
}
}
if (allmissing) {
a = 1.0f;
b = 0.0f;
}
else {
a = (float) ((max - min) / 254.0);
b = min;
}
// return results
for (i=0; i max) max = data[j];
j++;
}
if (min < gridmin) gridmin = min;
if (max > gridmax) gridmax = max;
levmin[lev] = min;
levmax[lev] = max;
}
// WLH 2-2-95
if (KLUDGE) {
// if the grid minimum is within delt of 0.0, fudge all values
// within delt of 0.0 to delt, and recalculate mins and maxes
float delt;
int nrncnl = nrnc * nl;
delt = (float) ((gridmax - gridmin) / 100000.0);
if (Math.abs(gridmin) < delt && gridmin != 0.0 && compressmode != 4) {
float min, max;
for (j=0; j= BIGVALUE && levmax[lev] <= SMALLVALUE) {
// all values in the layer are MISSING
d[lev] = 0.0f;
}
else {
d[lev] = levmax[lev] - levmin[lev];
}
if (d[lev] > dmax) dmax = d[lev];
}
// compute ga (scale) and gb (bias) for each grid level
if (dmax == 0.0) {
// special cases
if (gridmin == gridmax) {
// whole grid is of same value
for (lev=0; lev 0.0000000001) {
d = b / a;
id = (int) Math.floor(d);
d = d - id;
aa = (float) (a * 0.000001);
}
else id = 1;
if (-254 <= id && id <= 0 && d < aa) {
for (i=0; i= 0);
V5Dassert(vr >= 0);
V5Dassert(time < NumTimes);
V5Dassert(vr < NumVars);
pos = FirstGridPos + time * SumGridSizes;
for (i=0; i MAXVARS) {
System.err.println("Too many variables: " + NumVars +
" (Maximum is " + MAXVARS + ")");
valid = false;
}
// Variable Names
for (i=0; iMAXTIMES) {
System.err.println("Too many timesteps: " + NumTimes +
" (Maximum is " + MAXTIMES + ")");
valid = false;
}
// Make sure timestamps are increasing
for (i=1; i 1) {
int j = (v5dHHMMSStoSeconds(TimeStamp[i - 1]) -
v5dHHMMSStoSeconds(TimeStamp[i - 2])) +
86400 * (v5dYYDDDtoDays(DateStamp[i - 1]) -
v5dYYDDDtoDays(DateStamp[i - 2]));
if (j > 0) inc = j;
}
time1 = time0 + inc;
date1 = date0;
if (time1 >= 86400) {
time1 = 0;
date1++;
}
DateStamp[i] = v5dDaysToYYDDD(date1);
TimeStamp[i] = v5dSecondsToHHMMSS(time1);
}
}
// Rows
if (Nr < 2) {
System.err.println("Too few rows: " + Nr + " (2 is minimum)");
valid = false;
}
/* Don't check on max rows in case user overrode defaults
else if (Nr > MAXROWS) {
System.err.println("Too many rows: " + Nr +
" (" + MAXROWS + " is maximum)");
valid = false;
}
*/
// Columns
if (Nc < 2) {
System.err.println("Too few columns: " + Nc + " (2 is minimum)");
valid = false;
}
/* Don't check on max columns in case user overrode defaults
else if (Nc > MAXCOLUMNS) {
System.err.println("Too many columns: " + Nc +
" (" + MAXCOLUMNS + " is maximum)");
valid = false;
}
*/
// Levels
maxnl = 0;
for (vr=0; vr MAXLEVELS) {
System.err.println("Too many levels for var " + VarName[vr] + ": " +
(Nl[vr] + LowLev[vr]) + " (" + MAXLEVELS + " is maximum)");
valid = false;
}
if (Nl[vr] + LowLev[vr] > maxnl) {
maxnl = Nl[vr] + LowLev[vr];
}
}
if (CompressMode != 1 && CompressMode != 2 && CompressMode != 4) {
System.err.println("Bad CompressMode: " + CompressMode +
" (must be 1, 2 or 4)");
valid = false;
}
switch (VerticalSystem) {
case 0:
case 1:
if (VertArgs[1] == 0.0) {
System.err.println("Vertical level increment is zero, " +
"must be non-zero");
valid = false;
}
break;
case 2:
// Check that Height values increase upward
for (i=1; i= Pressure[" + (i-1) +
"]=" + height_to_pressure(VertArgs[i-1]) +
", level pressures must decrease");
valid = false;
break;
}
}
break;
default:
System.err.println("VerticalSystem = " + VerticalSystem +
", must be in 0..3");
valid = false;
}
switch (Projection) {
case 0: // Generic
if (ProjArgs[2] == 0.0) {
System.err.println("Row Increment (ProjArgs[2]) can't be zero");
valid = false;
}
if (ProjArgs[3] == 0.0) {
System.err.println("Column increment (ProjArgs[3]) can't be zero");
valid = false;
}
break;
case 1: // Cylindrical equidistant
if (ProjArgs[2] < 0.0) {
System.err.println("Row Increment (ProjArgs[2]) = " +
ProjArgs[2] + " (must be >=0.0)");
valid = false;
}
if (ProjArgs[3] <= 0.0) {
System.err.println("Column Increment (ProjArgs[3]) = " +
ProjArgs[3] + " (must be >=0.0)");
valid = false;
}
break;
case 2: // Lambert Conformal
if (ProjArgs[0] < -90.0 || ProjArgs[0] > 90.0) {
System.err.println("Lat1 (ProjArgs[0]) out of range: " + ProjArgs[0]);
valid = false;
}
if (ProjArgs[1] < -90.0 || ProjArgs[1] > 90.0) {
System.err.println("Lat2 (ProjArgs[1] out of range: " + ProjArgs[1]);
valid = false;
}
if (ProjArgs[5] <= 0.0) {
System.err.println("ColInc (ProjArgs[5]) = " +
ProjArgs[5] + " (must be >=0.0)");
valid = false;
}
break;
case 3: // Stereographic
if (ProjArgs[0] < -90.0 || ProjArgs[0] > 90.0) {
System.err.println("Central Latitude (ProjArgs[0]) out of range: " +
ProjArgs[0] + " (must be in +/-90)");
valid = false;
}
if (ProjArgs[1] < -180.0 || ProjArgs[1] > 180.0) {
System.err.println("Central Longitude (ProjArgs[1]) out of range: " +
ProjArgs[1] + " (must be in +/-180)");
valid = false;
}
if (ProjArgs[4] < 0) {
System.err.println("Column spacing (ProjArgs[4]) = " +
ProjArgs[4] + " (must be positive)");
valid = false;
}
break;
case 4: // Rotated
// WLH 4-21-95
if (ProjArgs[2] <= 0.0) {
System.err.println("Row Increment (ProjArgs[2]) = " +
ProjArgs[2] + " (must be >=0.0)");
valid = false;
}
if (ProjArgs[3] <= 0.0) {
System.err.println("Column Increment = (ProjArgs[3]) " +
ProjArgs[3] + " (must be >=0.0)");
valid = false;
}
if (ProjArgs[4] < -90.0 || ProjArgs[4] > 90.0) {
System.err.println("Central Latitude (ProjArgs[4]) out of range: " +
ProjArgs[4] + " (must be in +/-90)");
valid = false;
}
if (ProjArgs[5] < -180.0 || ProjArgs[5] > 180.0) {
System.err.println("Central Longitude (ProjArgs[5]) out of range: " +
ProjArgs[5] + " (must be in +/-180)");
valid = false;
}
if (ProjArgs[6] < -180.0 || ProjArgs[6] > 180.0) {
System.err.println("Central Longitude (ProjArgs[6]) out of range: " +
ProjArgs[6] + " (must be in +/-180)");
valid = false;
}
break;
default:
System.err.println("Projection = " + Projection + ", must be in 0..4");
valid = false;
}
return valid;
}
/** Get the McIDAS file number and grid number associated with the grid
identified by time and var.
@param time timestep
@param vr variable
@param mcfile one-element int array for storing McIDAS grid file number
@param mcgrid one-element int array for storing McIDAS grid number
*/
boolean v5dGetMcIDASgrid(int time, int vr, int[] mcfile, int[] mcgrid) {
if (time < 0 || time >= NumTimes) {
System.err.println("Bad time argument to v5dGetMcIDASgrid: " + time);
return false;
}
if (vr < 0 || vr >= NumVars) {
System.err.println("Bad var argument to v5dGetMcIDASgrid: " + vr);
return false;
}
mcfile[0] = (int) McFile[time][vr];
mcgrid[0] = (int) McGrid[time][vr];
return true;
}
/** Set the McIDAS file number and grid number associated with the grid
identified by time and var.
@param time timestep
@param vr variable
@param mcfile McIDAS grid file number
@param mcgrid McIDAS grid number
@return true = ok, false = error (bad time or var)
*/
boolean v5dSetMcIDASgrid(int time, int vr, int mcfile, int mcgrid) {
if (time < 0 || time >= NumTimes) {
System.err.println("Bad time argument to v5dSetMcIDASgrid: " + time);
return false;
}
if (vr < 0 || vr >= NumVars) {
System.err.println("Bad var argument to v5dSetMcIDASgrid: " + vr);
return false;
}
McFile[time][vr] = (short) mcfile;
McGrid[time][vr] = (short) mcgrid;
return true;
}
// ******************************************************************** //
// **** Input Functions **** //
// ******************************************************************** //
/** Read the header from a COMP* file and return results in the V5DStruct.
@return true = ok, false = error.
*/
boolean read_comp_header() throws IOException {
int id;
RandomAccessFile f = FileDesc;
// reset file position to start of file
f.seek(0);
// read file ID
id = f.readInt();
if (id == 0x80808080 || id == 0x80808081) {
// Older COMP5D format
int gridtimes, gridparms;
int i, j, it, iv, nl;
int gridsize;
float hgttop, hgtinc;
if (id == 0x80808080) {
// 20 vars, 300 times
gridtimes = 300;
gridparms = 20;
}
else {
// 30 vars, 400 times
gridtimes = 400;
gridparms = 30;
}
FirstGridPos = 12 * 4 + 8 * gridtimes + 4 * gridparms;
NumTimes = f.readInt();
NumVars = f.readInt();
Nr = f.readInt();
Nc = f.readInt();
nl = f.readInt();
for (i=0; i0; j--) {
if (name[j] == ' ' || name[j] == 0) name[j] = 0;
else break;
}
System.arraycopy(name, 0, VarName[i], 0, 4);
VarName[i][4] = 0;
}
gridsize = ((Nr * Nc * nl + 3) / 4) * 4;
for (i=0; i MaxVal[iv]) MaxVal[iv] = max;
}
}
// done
}
else if (id == 0x80808082 || id == 0x80808083) {
// Newer COMP5D format
int gridtimes, gridsize;
int it, iv, nl, i, j;
float delta = 0f;
gridtimes = f.readInt();
NumVars = f.readInt();
NumTimes = f.readInt();
Nr = f.readInt();
Nc = f.readInt();
nl = f.readInt();
for (i=0; i 1) {
if (delta != (VertArgs[i] - VertArgs[i - 1])) {
VerticalSystem = 2;
}
}
}
if (VerticalSystem == 1) VertArgs[1] = delta;
// read variable names
for (iv=0; iv0; j--) {
if (name[j] == ' ' || name[j] == 0) name[j] = 0;
else break;
}
System.arraycopy(name, 0, VarName[iv], 0, 8);
VarName[iv][8] = 0;
}
for (iv=0; iv= 0x80808080 && id <= 0x80808083) {
// this is an old COMP* file
FileFormat = id;
return read_comp_header();
}
else if (order == f.BIG_ENDIAN) {
order = f.LITTLE_ENDIAN;
continue; // try again
} else {
// unknown file type
System.out.println("unknown file type");
return false;
}
}
// default
CompressMode = 1;
while (!end_of_header) {
int tag, length;
int i, time, nl, lev;
tag = f.readInt();
length = f.readInt();
switch (tag) {
case TAG_VERSION:
V5Dassert(length == 10);
byte[] b = new byte[10];
f.read(b, 0, 10);
int index = 10;
for (int q=0; q<10; q++) {
if (b[q] == 0) {
index = q;
break;
}
}
FileVersion = new String(b, 0, index);
// Check if reading a file made by a future version of Vis5D
if (FileVersion.compareTo(FILE_VERSION) > 0) {
System.err.println("Warning: Trying to read a version " +
FileVersion + " file, you should upgrade Vis5D.");
}
break;
case TAG_NUMTIMES:
V5Dassert(length == 4);
NumTimes = f.readInt();
break;
case TAG_NUMVARS:
V5Dassert(length == 4);
NumVars = f.readInt();
break;
case TAG_VARNAME:
// 1 int + 10 char
V5Dassert(length == 14);
vr = f.readInt();
for (int q=0; q<10; q++) VarName[vr][q] = (char) f.readByte();
break;
case TAG_NR:
// Number of rows for all variables
V5Dassert(length == 4);
Nr = f.readInt();
break;
case TAG_NC:
// Number of columns for all variables
V5Dassert(length == 4);
Nc = f.readInt();
break;
case TAG_NL:
// Number of levels for all variables
V5Dassert(length == 4);
nl = f.readInt();
for (i=0; i 3) {
System.err.println("Error: bad vertical coordinate system: " +
VerticalSystem);
}
break;
case TAG_VERT_ARGS:
numargs = f.readInt();
V5Dassert(numargs <= MAXVERTARGS);
for (int q=0; q 4) {
System.err.println("Error while reading header, bad projection (" +
Projection + ")");
return false;
}
break;
case TAG_PROJ_ARGS:
numargs = f.readInt();
V5Dassert(numargs <= MAXPROJARGS);
for (int q=0; q= NumVars) {
throw new IOException("Error in v5dReadCompressedGrid: " +
"bad var argument (" + vr + ")");
}
if (FileFormat != 0) {
// old COMP* file
return read_comp_grid(time, vr, ga, gb, compdata);
}
// move to position in file
pos = grid_position(time, vr);
FileDesc.seek(pos);
// read ga, gb arrays
read_float4_array(FileDesc, ga, Nl[vr]);
read_float4_array(FileDesc, gb, Nl[vr]);
// read compressed grid data
n = Nr * Nc * Nl[vr];
if (CompressMode == 1) {
k = read_block(FileDesc, compdata, n, 1) == n;
}
else if (CompressMode == 2) {
k = read_block(FileDesc, compdata, n, 2) == n;
}
else if (CompressMode == 4) {
k = read_block(FileDesc, compdata, n, 4) == n;
}
if (!k) {
// error
System.err.println("Error in v5dReadCompressedGrid: " +
"read failed, bad file?");
}
// n = Nr * Nc * Nl[vr] * CompressMode;
// if (FileDesc.read(compdata, 0, n) != n)
// throw new IOException("Error in v5dReadCompressedGrid: read failed");
return k;
}
/** Read a grid from a v5d file, decompress it and return it.
@param time timestep
@param vr variable
@param data array to put grid data
@return true = ok, false = error.
*/
boolean v5dReadGrid(int time, int vr, float[] data)
throws IOException, BadFormException {
float[] ga = new float[MAXLEVELS];
float[] gb = new float[MAXLEVELS];
byte[] compdata;
int bytes;
if (time < 0 || time >= NumTimes) {
System.err.println("Error in v5dReadGrid: " +
"bad timestep argument (" + time + ")");
return false;
}
if (vr < 0 || vr >= NumVars) {
System.err.println("Error in v5dReadGrid: " +
"bad variable argument (" + vr + ")");
return false;
}
// allocate compdata buffer
if (CompressMode == 1) {
/*-TDR, bug? factor should be 1
bytes = Nr * Nc * Nl[vr] * 2; // sizeof(unsigned char);
*/
bytes = Nr * Nc * Nl[vr] * 1; // sizeof(unsigned char);
}
else if (CompressMode == 2) {
bytes = Nr * Nc * Nl[vr] * 2; // sizeof(unsigned short);
}
else if (CompressMode == 4) {
bytes = Nr * Nc * Nl[vr] * 4; // sizeof(float);
}
else {
System.err.println("Error in v5dReadGrid: " +
"bad compression mode (" + CompressMode + ")");
return false;
}
compdata = new byte[bytes];
// read the compressed data
if (!v5dReadCompressedGrid(time, vr, ga, gb, compdata)) return false;
// decompress the data
v5dDecompressGrid(Nr, Nc, Nl[vr], CompressMode, compdata, ga, gb, data);
return true;
}
// ******************************************************************** //
// **** Output Functions **** //
// ******************************************************************** //
boolean write_tag(int tag, int length, boolean newfile) throws IOException {
if (!newfile) {
// have to check that there's room in header to write this tagged item
if (CurPos+8+length > FirstGridPos) {
System.err.println("Error: out of header space!");
// Out of header space!
return false;
}
}
FileDesc.writeInt(tag);
FileDesc.writeInt(length);
CurPos += 8 + length;
return true;
}
/** Write the information in the given V5DStruct as a v5d file header.
Note that the current file position is restored when this function
returns normally.
@return true = ok, false = error.
*/
boolean write_v5d_header() throws IOException {
int vr, time, filler, maxnl;
RandomAccessFile f;
boolean newfile;
if (FileFormat != 0) {
System.err.println("Error: " +
"v5d library can't write comp5d format files.");
return false;
}
f = FileDesc;
if (!v5dVerifyStruct()) return false;
// Determine if we're writing to a new file
newfile = (FirstGridPos == 0);
// compute grid sizes
SumGridSizes = 0;
for (vr=0; vr maxnl) maxnl = Nl[vr]+LowLev[vr];
}
// Min/Max values
for (vr=0; vr= NumTimes) {
System.err.println("Error in v5dWriteCompressedGrid: " +
"bad timestep argument (" + time + ")");
return false;
}
if (vr < 0 || vr >= NumVars) {
System.err.println("Error in v5dWriteCompressedGrid: " +
"bad variable argument (" + vr + ")");
return false;
}
// move to position in file
pos = grid_position(time, vr);
FileDesc.seek(pos);
// write ga, gb arrays
k = false;
for (int q=0; q= NumTimes) {
System.err.println("Error in v5dWriteGrid: " +
"bad timestep argument (" + time + ")");
return false;
}
if (vr < 0 || vr >= NumVars) {
System.err.println("Error in v5dWriteGrid: " +
"bad variable argument (" + vr + ")");
return false;
}
// allocate compdata buffer
if (CompressMode == 1) {
bytes = Nr * Nc * Nl[vr] * 2; // sizeof(unsigned char);
}
else if (CompressMode == 2) {
bytes = Nr * Nc * Nl[vr] * 2; // sizeof(unsigned short);
}
else if (CompressMode == 4) {
bytes = Nr * Nc * Nl[vr] * 4; // sizeof(float);
}
else {
System.err.println("Error in v5dWriteGrid: " +
"bad compression mode (" + CompressMode + ")");
return false;
}
compdata = new byte[bytes];
// compress the grid data
float[] min1 = new float[1];
float[] max1 = new float[1];
v5dCompressGrid(Nr, Nc, Nl[vr], CompressMode, data, compdata,
ga, gb, min1, max1);
min = min1[0];
max = max1[0];
// update min and max value
if (min < MinVal[vr]) MinVal[vr] = min;
if (max > MaxVal[vr]) MaxVal[vr] = max;
// write the compressed grid
return v5dWriteCompressedGrid(time, vr, ga, gb, compdata);
}
/** Close a v5d file which was opened with open_v5d_file() or
create_v5d_file().
@return true = ok, false = error
*/
boolean v5dCloseFile() throws IOException {
boolean status = true;
if (Mode == 'w') {
// rewrite header because writing grids updates minval and maxval fields
FileDesc.seek(0);
status = write_v5d_header();
// CTR: is this seek necessary?
FileDesc.seek(FileDesc.length());
FileDesc.close();
}
else if (Mode == 'r') {
// just close the file
FileDesc.close();
}
else {
System.err.println("Error in v5dCloseFile: bad V5DStruct argument");
return false;
}
FileDesc = null;
Mode = 0;
return status;
}
}