[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
20030801: IDV 2D Display only on Linux?
- Subject: 20030801: IDV 2D Display only on Linux?
- Date: Fri, 01 Aug 2003 14:32:16 -0600
To: address@hidden
From: "Todd Plessel" <address@hidden>
Subject: IDV 2D Display only on Linux?
Organization: EPA
Keywords: 200308010054.h710sOLd023456 IDV Linux
Hi Todd-
Hope you're back from a wonderful vacation.
It was tough to come back. ;-)
Now about IDV:
I noticed that when viewing a 3D Vis5D file on a Linux host
that IDV uses a 2D display instead of a 3D display which
precludes 3D visualizations such as isosurfaces.
Are you running this from a local build or from the
InstallAnywhere version? If local, do you have Java 3D installed?
I just tried with the InstallAnywhere version and it worked
fine.
Likewise, when a 1 layer grid is read in there are no Fields (e.g., 2D)
listed so no displays can be made.
Hmm, that is odd. For the file I tried, it listed the 2D fields.
Could you send a sample file?
Any progress on figuring-out why the 3D grid appears below
the map surface and why the Color Shaded Plan View doesn't appear?
I have not looked at this since I left. I'm still catching up
and Stu's out sick today. I'll have to review your previous
e-mail and look into this.
Where you able to display those sample data files (profiler, raob, etc.)?
Normally, the point data (madis, metar, maritime) files would be read
in by the ucar.unidata.data.point.NetcdfMetarDataSource (not a good
name, but was first only for Metar). There are a couple
of problems with these files. First there was some ill concieved
logic in NetcdfMetarDataSource for picking out the observation data
that are indexed on recnum. The other problem is with the date variable.
NetcdfMetarDataSource has a list of possible time variables to
use and none of the ones in the files were in the list. Adding
those revealed the next problem, namely that the unit for time
is invalid (seconds since 1-1-1970). This does not conform to
the ISO standard and really says seconds since year 1, month 1,
the 1970th day. I put a hack into NetcdfMetarDataSource which
will assume seconds since 1970-1-1. I've attached a version
which should allow you to read in all the point files. You'll
need to create your own station models for the parameters you
want to view (Edit/Station models menu) or add the specific parameters
to the parameter aliases that are used in the default models
(Edit/Parameter aliases menu).
I was able to display skew-Ts from the RAOB file using the file
selector under the RAOB tab. However, the times being used are the
release times and it's not handling the ones with a fill
value very well. I'm doing some work on the sounding adapter
anyway, so will fix this as well. Actually, I've attached a
version that fixes the problem. I've changed it to look for
the global attribute "timeVariables" to figure out what
time var to use and default to the old one. It also will
handle units on the times (defaulting to seconds since
the epoch). Some of the obs are bad and there are nasty
error messages that pop up when you try to display these.
I'll work on making that a little nicer as I continue working
on the sounding adapter.
If you want plan view plots of soundings, that will require
a new adapter. We need to do that in the future, but it's
not on our immediate radar screen.
For the profiler data, you would need to write a new adapter.
Currently, we only plot profiler data from an ADDE server.
In GEMPAK and McIDAS, we decode these netCDF files into
their formats and in the process, "normalize" the data so
that all heights are MSL instead of AGL, throw out missing
values, etc. So, we opted to take the easy route and get
the processed data from an ADDE server.
Do I need to write a Convention or an Adapter for these NetCDF files
or do they already exist?
Please let me know any progress so I can report on it.
Send me the vis5d file and I'll get back to you next week
on your other issue.
Don
*************************************************************
Don Murray UCAR Unidata Program
address@hidden P.O. Box 3000
(303) 497-8628 Boulder, CO 80307
http://www.unidata.ucar.edu/staff/donm
*************************************************************
// $Id: NetcdfMetarDataSource.java,v 1.3 2002/10/29 00:25:48 jeffmc Exp $
/*
* Copyright 1997-2001 Unidata Program Center/University Corporation for
* Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
* address@hidden.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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 ucar.unidata.data.point;
import java.util.Hashtable;
import ucar.unidata.data.*;
import ucar.unidata.util.Misc;
import ucar.unidata.util.LogUtil;
import java.rmi.RemoteException;
import edu.wisc.ssec.mcidas.McIDASUtil;
import visad.*;
import visad.georef.EarthLocation;
import visad.georef.EarthLocationTuple;
import visad.data.netcdf.Plain;
import org.apache.log4j.Category;
/**
* A data source for ADDE point data
*
* @author Don Murray
* @version $Revision: 1.3 $ $Date: 2002/10/29 00:25:48 $
*/
public class NetcdfMetarDataSource extends DataSourceImpl {
static Category log_ =
Category.getInstance (NetcdfMetarDataSource.class.getName());
private String source;
private String[] timeVars = {"time_nominal",
"time_Nominal",
"timeNominal",
"timeObs",
"reportTime",
"time"};
public NetcdfMetarDataSource ()
throws VisADException {
init ();
}
public NetcdfMetarDataSource(DataSourceDescriptor descriptor, String
source, Hashtable properties)
throws VisADException {
super (descriptor, source, "Netcdf Metar Data", properties);
this.source = source;
try {
init ();
} catch (VisADException exc) {
setInError (true);
throw exc;
}
}
private void init ()
throws VisADException {
}
public void doMakeDataChoices() {
DataChoice choice =
new DirectDataChoice (this, source, "Station Model Plot", "Station
Data Plot",
DataCategory.parseCategories
(DataCategory.CATEGORY_POINT+";StationPlot", false), null);
addDataChoice(choice);
}
protected Data getDataInner (DataChoice dataChoice, DataCategory category,
DataSelection dataSelection)
throws VisADException, RemoteException
{
try {
return makeObs(dataChoice, dataSelection);
} catch (Exception exc) {
logException ("Creating obs", exc);
}
return null;
}
private FieldImpl makeObs (DataChoice dataChoice, DataSelection subset)
throws Exception {
String source = (String) dataChoice.getId ();
// FieldImpl obs = (FieldImpl) getCache (source);
FieldImpl obs = null;
if (obs == null) {
Plain plain = new Plain(true); // true = convert char to Text
obs = makePointObs(plain.open(source));
//putCache (source, obs);
}
return obs;
}
/**
* Check to see if this NetcdfMetarDataSource is equal to the object
* in question.
* @param o object in question
* @return true if they are the same or equivalent objects
*/
public boolean equals(Object o) {
if (!(o instanceof NetcdfMetarDataSource)) return false;
NetcdfMetarDataSource that = (NetcdfMetarDataSource) o;
return (this == that);
}
public int hashCode() {
int hashCode = getName().hashCode();
return hashCode;
}
/**
* Take a field of data and turn it into a field of PointObs. Right
* now, this assumes a surface data from an metar2nc type netCDF file
* or similar (i.e. AWIPS). We use the FieldImpl that has domain
* recNum().
* @return field of PointObs
*/
private FieldImpl makePointObs(Data input)
throws VisADException {
long millis = System.currentTimeMillis();
FieldImpl retField = null;
try {
// first check to see if we can make a location ob
// input has to have a FieldImpl as one component of the
// form (recNum -> (parm1, parm2, parm3, ...., parmN))
FieldImpl recNumObs = null;
RealType recNum = RealType.getRealType("recNum");
MathType inputType = input.getType();
if (input instanceof Tuple) {
TupleType tt = (TupleType) input.getType();
for (int i = 0; i < tt.getDimension(); i++) {
MathType compType = tt.getComponent(i);
if ((compType instanceof FunctionType)) {
RealTupleType domType = ((FunctionType)compType).getDomain();
if (domType.getDimension() == 1 &&
recNum.equals(domType.getComponent(0))) {
recNumObs = (FieldImpl) ((Tuple) input).getComponent(i);
break;
}
}
}
} else if ((inputType instanceof FunctionType) &&
(recNum.equals(((FunctionType)inputType).getDomain()))) {
recNumObs = (FieldImpl) input;
}
if (recNumObs == null) {
throw new IllegalArgumentException(
"don't know how to convert input to a point ob");
}
TupleType type;
Gridded1DSet indexSet = null;
try {
type = (TupleType) ((FunctionType)recNumObs.getType()).getRange();
indexSet = (Gridded1DSet) recNumObs.getDomainSet();
}
catch (ClassCastException ce) {
throw new IllegalArgumentException(
"don't know how to convert input to a point ob");
}
//System.out.println(indexSet.getLength() + " obs");
long mil2 = System.currentTimeMillis();
boolean allReals = (type instanceof RealTupleType);
// check for time
int timeIndex = -1;
for (int i = 0; i < timeVars.length; i++) {
timeIndex = type.getIndex(timeVars[i]);
if (timeIndex > -1) break;
}
if (timeIndex == -1) {
throw new IllegalArgumentException("can't find DateTime components");
}
// Check for LAT/LON/ALT
int latIndex = type.getIndex(RealType.Latitude);
int lonIndex = type.getIndex(RealType.Longitude);
int altIndex = type.getIndex(RealType.Altitude);
//if (altIndex == -1) altIndex = type.getIndex("elev");
if (latIndex == -1 || lonIndex == -1) {
throw new IllegalArgumentException("can't find lat/lon");
}
int[] indicies = new int[] {timeIndex, latIndex,
lonIndex, altIndex};
int numVars = type.getDimension();
int numNotRequired = numVars - ((altIndex != -1)?4:3);
//System.out.println("Of " + numVars + " vars, " + numNotRequired +
// " are not required");
int[] notReqIndices = new int[numNotRequired];
int l = 0;
for (int i = 0; i < numVars; i++) {
if (i != timeIndex && i != latIndex &&
i != lonIndex && i != altIndex ) {
notReqIndices[l++] = i;
}
}
//System.out.println("Setup took " + (System.currentTimeMillis() - mil2));
PointOb[] obs = new PointObTuple[indexSet.getLength()];
for (int i = 0; i < indexSet.getLength(); i++) {
mil2 = System.currentTimeMillis();
Tuple ob = (Tuple) recNumObs.getSample(i);
// get location
EarthLocation location =
new EarthLocationTuple(
(Real) ob.getComponent(latIndex),
(Real) ob.getComponent(lonIndex),
(altIndex != -1)
? (Real) ob.getComponent(altIndex)
: new Real(RealType.Altitude, 0));
/*
// get DateTime
DateTime dateTime = new DateTime((Real)ob.getComponent(timeIndex));
*/
// get DateTime. Must have valid time unit. If not assume
// seconds since epoch. Maybe we should throw an error?
Real timeVal = (Real)ob.getComponent(timeIndex);
DateTime dateTime = null;
if (timeVal.getUnit() != null) {
dateTime = new DateTime(timeVal);
} else { // assume seconds since epoch
dateTime = new DateTime(timeVal.getValue());
}
// now make data
Data[] others = (allReals == true)
? new Real[numNotRequired]
: new Data[numNotRequired];
for (int j = 0; j < numNotRequired; j++) {
others[j] = (allReals == true)
? (Real) ob.getComponent(notReqIndices[j])
: (Data) ob.getComponent(notReqIndices[j]);
}
Data rest = (allReals == true)
? new RealTuple((Real[]) others)
: new Tuple(others, false);
//obs[i] = new PointObField(location, dateTime, rest);
obs[i] = new PointObTuple(location, dateTime, rest);
//System.out.println("made data in " + (System.currentTimeMillis() -
mil2));
}
retField =
new FieldImpl(
new FunctionType(((SetType)indexSet.getType()).getDomain(),
obs[0].getType()), indexSet);
retField.setSamples(obs, false);
} catch (RemoteException re) {
throw new VisADException("got RemoteException " + re);
}
//System.out.println("Making point obs took " + (System.currentTimeMillis()
- millis));
return retField;
}
public void setSource (String value) {
source = value;
}
public String getSource () {
return source;
}
}
// $Id: NetcdfSoundingAdapter.java,v 1.8 2002/08/30 22:31:34 jeffmc Exp $
/*
* Copyright 1997-2000 Unidata Program Center/University Corporation for
* Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
* address@hidden.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 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 Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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 ucar.unidata.data.sounding;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import ucar.netcdf.*;
import ucar.unidata.metdata.Station;
import ucar.unidata.data.sounding.RAOB;
import ucar.unidata.data.sounding.SoundingOb;
import ucar.unidata.data.sounding.SoundingStation;
import ucar.unidata.util.Defaults;
import ucar.visad.quantities.GeopotentialAltitude;
import visad.*;
import visad.data.units.Parser;
/**
* This class creates VisAD compatible data objects from a netCDF
* file of upper air soundings.
*
* @author Don Murray, Unidata/UCAR
*/
public class NetcdfSoundingAdapter extends SoundingAdapterImpl
implements SoundingAdapter
{
private String filename;
private NetcdfFile nc = null;
private int numStations; // number of stations in file
private String prMandPVar; // name of mandP pressure variable
private String htMandPVar; // name of mandP height variable
private String tpMandPVar; // name of mandP temp variable
private String tdMandPVar; // name of mandP dewpt variable
private String spdMandPVar; // name of mandP wind speed variable
private String dirMandPVar; // name of mandP wind dir variable
private String htMandWVar; // name of mandW height variable
private String spdMandWVar; // name of mandW wind speed variable
private String dirMandWVar; // name of mandW wind dir variable
private String prSigTVar; // name of sig T pressure variable
private String tpSigTVar; // name of sig T temp variable
private String tdSigTVar; // name of sig T dewpt variable
private String htSigWVar; // name of sig wind height variable
private String spdSigWVar; // name of sig wind wind speed variable
private String dirSigWVar; // name of sig wind wind dir variable
private String prMaxWVar; // name of max wind pressure variable
private String spdMaxWVar; // name of max wind wind speed variable
private String dirMaxWVar; // name of max wind wind dir variable
private String prTropVar; // name of tropopause pressure variable
private String tpTropVar; // name of tropopause temp variable
private String tdTropVar; // name of tropopause dewpt variable
private String spdTropVar; // name of tropopause wind speed variable
private String dirTropVar; // name of tropopause wind dir variable
private Variable stid; // station id
private Variable lat; // station latitude
private Variable lon; // station longitude
private Variable elev; // station elevation
private Variable time; // sounding time
private Variable numMandP; // number mandatory pressure levels
private Variable numMandW; // number mandatory wind levels
private Variable numSigT; // number significant temp levels
private Variable numSigW; // number of significant wind levels
private Variable numMaxW; // number of max wind levels
private Variable numTrop; // number of tropopause levels
private boolean hasMandP = false; // file has mandatory pressure data
private boolean hasMandW = false; // file has mandatory wind data
private boolean hasSigT = false; // file has significant temp data
private boolean hasSigW = false; // file has significant wind data
private boolean hasMaxW = false; // file has max wind data
private boolean hasTrop = false; // file has tropopause data
private boolean oneTrop = false; // file has tropopause data in
// old format (only one)
private boolean
dewpointIsDepression = true; // file stores dewpoint as value
private float missingValue = 99999.f; // default missing value
private Unit timeUnit = null;
private double timeFill = Double.NaN;
private SoundingStation s;
private File myFile;
/**
ctor for reflection based construction
**/
public NetcdfSoundingAdapter() {
super ("NetcdfSoundingAdapter");
}
/**
* Read a netCDF file of decoded soundings.
*
* @param filename the fully qualified path and name of the file
* to be adapted.
*/
public NetcdfSoundingAdapter (String filename) throws Exception {
this (new File (filename));
}
public NetcdfSoundingAdapter (File file)
throws Exception {
super ("NetcdfSoundingAdapter");
myFile = file;
filename = myFile.getAbsolutePath();
init ();
}
public void update () {
try {
haveInitialized = false;
init ();
} catch (Exception exc) {
logException ("Doing update", exc);
}
}
/**
* Read a netCDF file of decoded soundings.
*
* @param filename the file to be adapted.
*/
protected void init () throws Exception {
if (haveInitialized) return;
super.init ();
try {
nc = new NetcdfFile(myFile, true);
// get the names of the variables to be used.
getVariables ();
// get the station list and number of stations
numStations = stid.getLengths()[0];
stations = new ArrayList (numStations); // array of stations
soundings = new ArrayList (numStations); // array of soundings
times = new ArrayList (10);
int index[] = new int[1]; // index array to specify which value
// fill the station and sounding lists
for (int i=0; i<numStations; i++) {
index[0] = i;
DateTime sndTime;
// Set the station (s)
try {
makeSoundingStation(index);
sndTime = getObsTime(index);
} catch (Exception e) {
continue;
}
// Set the data
if (sndTime != null) makeSoundingOb(index, s, sndTime);
}
Collections.sort(times);
} catch (Exception ne) {
logException ("Unable to read upper air netCDF file", ne);
}
}
public String getSource () {
return filename;
}
public void setSource (String s) {
filename = s;
myFile =new File (s);
}
/** check to see if the RAOB has any data */
public SoundingOb initSoundingOb (SoundingOb sound) {
checkInit ();
if (!sound.hasData ()) {
int idx = soundings.indexOf (sound);
if (idx <0) {
throw new IllegalArgumentException ("SoundingAdapter does not
contain sounding:" + sound);
}
setRAOBData (new int[] {idx}, sound);
}
return sound;
}
/** create a sounding station object from the netCDF file info */
private void makeSoundingStation(int[] index)
throws Exception {
String wmoID;
double latvalue;
double lonvalue;
double elevvalue;
try {
wmoID = Integer.toString(stid.getInt(index));
latvalue = lat.getDouble(index);
lonvalue = lon.getDouble(index);
elevvalue = elev.getDouble(index);
} catch (Exception ne) {
throw new Exception(ne.toString());
}
s = new SoundingStation (wmoID, latvalue, lonvalue, elevvalue);
stations.add(s);
}
/** Creates a sounding observation with an empty raob */
private void makeSoundingOb (int [] index, SoundingStation station,
DateTime sndTime) {
soundings.add (new SoundingOb (station, sndTime));
if (!times.contains(sndTime)) times.add(sndTime);
}
/** Fills in the data for the RAOB */
private void setRAOBData (int [] index, SoundingOb sound) {
Variable press;
Variable height;
Variable temp;
Variable dewpt;
Variable direct;
Variable speed;
Unit pUnit = null;
Unit tUnit = null;
Unit tdUnit = null;
Unit spdUnit = null;
Unit dirUnit = null;
Unit zUnit = null;
int i;
int numLevels;
float p[];
float t[];
float td[];
float z[];
float spd[];
float dir[];
int[] j = new int [2];
j[0] = index[0];
int levFill;
float pFill;
float zFill;
float tpFill;
float tdFill;
float spdFill;
float dirFill;
dbPrint ("\nNew Station:\n\t" + sound.getStation());
// get the mandatory levels first
if (hasMandP) {
try {
numLevels = numMandP.getInt(index);
levFill = (int) getFillValue(numMandP, missingValue);
if (numLevels > 0 && numLevels != levFill) {
dbPrint ("Num mand pressure levels = " + numLevels);
// Get the variables and their units
press = nc.get(prMandPVar);
pUnit = getUnit(press);
pFill = getFillValue(press, missingValue);
height = nc.get(htMandPVar);
// NB: geopotential altitudes stored in units of length
zUnit =
GeopotentialAltitude.getGeopotentialUnit(
getUnit(height));
zFill = getFillValue(height, missingValue);
temp = nc.get(tpMandPVar);
tUnit = getUnit(temp);
tpFill = getFillValue(temp, missingValue);
dewpt = nc.get(tdMandPVar);
tdUnit = getUnit(dewpt);
tdFill = getFillValue(dewpt, missingValue);
speed = nc.get(spdMandPVar);
spdUnit = getUnit(speed);
spdFill = getFillValue(speed, missingValue);
direct = nc.get(dirMandPVar);
dirUnit = getUnit(direct);
dirFill = getFillValue(direct, missingValue);
// initialize the arrays
p = new float[numLevels];
z = new float[numLevels];
t = new float[numLevels];
td = new float[numLevels];
spd = new float[numLevels];
dir = new float[numLevels];
// fill the arrays
for (i = 0; i < numLevels; i++) {
j[1] = i;
p[i] = press.getFloat(j) == pFill
? Float.NaN
: press.getFloat(j);
z[i] = height.getFloat(j) == zFill
? Float.NaN
: height.getFloat(j);
t[i] = temp.getFloat(j) == tpFill
? Float.NaN
: temp.getFloat(j);
td[i] =
dewpt.getFloat(j) == tdFill
? Float.NaN
: dewpointIsDepression == true
? t[i] - dewpt.getFloat(j)
: dewpt.getFloat(j);
spd[i] = speed.getFloat(j) == spdFill
? Float.NaN
: speed.getFloat(j);
dir[i] = direct.getFloat(j) == dirFill
? Float.NaN
: direct.getFloat(j);
}
sound.getRAOB().setMandatoryPressureProfile(pUnit, p,
tUnit, t, tdUnit, td, spdUnit, spd,
dirUnit, dir,
zUnit, z);
}
else if (debug) {
System.out.println("No mandatory pressure data found for
this station");
}
} catch (Exception e) {
logException ("Unable to set mandatory pressure data for
station " + sound.getStation(), e);
}
}
// now get the mandatory wind data
if (hasMandW) {
try {
numLevels = numMandW.getInt(index);
levFill = (int) getFillValue(numMandW, missingValue);
if (numLevels > 0 && numLevels != levFill) {
if (debug)
System.out.println("Num mand wind levels = "+
numLevels);
// Get the variables and their units
height = nc.get(htMandWVar);
// NB: geopotential altitudes stored in units of length
zUnit =
GeopotentialAltitude.getGeopotentialUnit(
getUnit(height));
zFill = getFillValue(height, missingValue);
speed = nc.get(spdMandWVar);
spdUnit = getUnit(speed);
spdFill = getFillValue(speed, missingValue);
direct = nc.get(dirMandWVar);
dirUnit = getUnit(direct);
dirFill = getFillValue(direct, missingValue);
// initialize the arrays
z = new float[numLevels];
spd = new float[numLevels];
dir = new float[numLevels];
// fill the arrays
for (i = 0; i < numLevels; i++) {
j[1] = i;
z[i] = height.getFloat(j) == zFill
? Float.NaN
: height.getFloat(j);
spd[i] = speed.getFloat(j) == spdFill
? Float.NaN
: speed.getFloat(j);
dir[i] = direct.getFloat(j) == dirFill
? Float.NaN
: direct.getFloat(j);
}
sound.getRAOB().setMandatoryWindProfile(zUnit, z, spdUnit,
spd, dirUnit, dir);
}
else if (debug)
System.out.println("No mandatory wind data found " +
"for this station");
} catch (Exception e) {
logException ("Unable to set mandatory wind data for station "
+ sound.getStation(), e);
}
}
// get the significant temperature levels
if (hasSigT) {
try {
numLevels = numSigT.getInt(index);
levFill = (int) getFillValue(numSigT, missingValue);
if (numLevels > 0 && numLevels != levFill) {
if (debug)
System.out.println("Num sig temperature levels = " +
numLevels);
// Get the variables and their units
press = nc.get(prSigTVar);
pUnit = getUnit(press);
pFill = getFillValue(press, missingValue);
temp = nc.get(tpSigTVar);
tUnit = getUnit(temp);
tpFill = getFillValue(temp, missingValue);
dewpt = nc.get(tdSigTVar);
tdUnit = getUnit(dewpt);
tdFill = getFillValue(dewpt, missingValue);
// initialize the arrays
p = new float[numLevels];
t = new float[numLevels];
td = new float[numLevels];
// fill the arrays
for (i = 0; i < numLevels; i++) {
j[1] = i;
p[i] = press.getFloat(j) == pFill
? Float.NaN
: press.getFloat(j);
t[i] = temp.getFloat(j) == tpFill
? Float.NaN
: temp.getFloat(j);
/*
td[i] = dewpt.getFloat(j) == tdFill
? Float.NaN
: dewpt.getFloat(j);
*/
td[i] = dewpt.getFloat(j) == tdFill
? Float.NaN
: dewpointIsDepression == true
? t[i] - dewpt.getFloat(j)
: dewpt.getFloat(j);
}
sound.getRAOB().setSignificantTemperatureProfile(pUnit, p,
tUnit, t, tdUnit, td);
}
else if (debug)
System.out.println("No sig temperature data found " +
"for this station");
} catch (Exception e) {
logException ("Unable to set significant temperature data for
station " + sound.getStation(), e);
}
}
// get the significant levels with respect to wind
if (hasSigW) {
try {
numLevels = numSigW.getInt(index);
levFill = (int) getFillValue(numSigW, missingValue);
if (numLevels > 0 && numLevels != levFill) {
if (debug)
System.out.println("Num significant wind levels = " +
numLevels);
// Get the variables and their units
height = nc.get(htSigWVar);
// NB: geopotential altitudes stored in units of length
zUnit =
GeopotentialAltitude.getGeopotentialUnit(
getUnit(height));
zFill = getFillValue(height, missingValue);
speed = nc.get(spdSigWVar);
spdUnit = getUnit(speed);
spdFill = getFillValue(speed, missingValue);
direct = nc.get(dirSigWVar);
dirUnit = getUnit(direct);
dirFill = getFillValue(direct, missingValue);
// initialize the arrays
z = new float[numLevels];
spd = new float[numLevels];
dir = new float[numLevels];
// fill the arrays
for (i = 0; i < numLevels; i++) {
j[1] = i;
z[i] = height.getFloat(j) == zFill
? Float.NaN
: height.getFloat(j);
spd[i] = speed.getFloat(j) == spdFill
? Float.NaN
: speed.getFloat(j);
dir[i] = direct.getFloat(j) == dirFill
? Float.NaN
: direct.getFloat(j);
}
sound.getRAOB().setSignificantWindProfile (zUnit, z,
spdUnit, spd, dirUnit, dir);
} else {
dbPrint ("No significant wind data found for this station");
}
} catch (Exception e) {
logException ("Unable to set significant wind data for station
" + sound.getStation(), e);
}
}
// now get the max wind level
if (hasMaxW) {
boolean multiLevel = false;
try {
numLevels = numMaxW.getInt(index);
levFill = (int) getFillValue(numMaxW, missingValue);
if (numLevels > 0 && numLevels != levFill) {
if (debug)
System.out.println("Num max wind levels = " +
numLevels);
// Get the variables and their units
press = nc.get(prMandPVar);
// check to see if it handles multipl levels
if (press.getRank() > 1) multiLevel = true;
pUnit = getUnit(press);
pFill = getFillValue(press, missingValue);
speed = nc.get(spdMandPVar);
spdUnit = getUnit(speed);
spdFill = getFillValue(speed, missingValue);
direct = nc.get(dirMandPVar);
dirUnit = getUnit(direct);
dirFill = getFillValue(direct, missingValue);
// initialize the arrays
p = new float[numLevels];
spd = new float[numLevels];
dir = new float[numLevels];
// fill the arrays
if (!multiLevel) j = new int[] {index[0]};
for (i = 0; i < numLevels; i++) {
if (multiLevel) j[1] = i;
p[i] = press.getFloat(j) == pFill
? Float.NaN
: press.getFloat(j);
spd[i] = speed.getFloat(j) == spdFill
? Float.NaN
: speed.getFloat(j);
dir[i] = direct.getFloat(j) == dirFill
? Float.NaN
: direct.getFloat(j);
}
sound.getRAOB().setMaximumWindProfile(pUnit, p, spdUnit,
spd, dirUnit, dir);
}
else if (debug)
System.out.println("No maximum wind data found " +
"for this station");
} catch (Exception e) {
logException ("Unable to set maximum wind data for station " +
sound.getStation(), e);
}
}
// get the tropopause levels
if (hasTrop) {
try {
numLevels = oneTrop ? 1 : numTrop.getInt(index);
levFill = oneTrop
? (int) missingValue
: (int) getFillValue(numTrop, missingValue);
if (numLevels > 0 && numLevels != levFill) {
if (debug) System.out.println("Num tropopause levels = " +
numLevels);
// Get the variables and their units
press = nc.get(prTropVar);
pUnit = getUnit(press);
pFill = getFillValue(press, missingValue);
temp = nc.get(tpTropVar);
tUnit = getUnit(temp);
tpFill = getFillValue(temp, missingValue);
dewpt = nc.get(tdTropVar);
tdUnit = getUnit(dewpt);
tdFill = getFillValue(dewpt, missingValue);
speed = nc.get(spdTropVar);
spdUnit = getUnit(speed);
spdFill = getFillValue(speed, missingValue);
direct = nc.get(dirTropVar);
dirUnit = getUnit(direct);
dirFill = getFillValue(direct, missingValue);
// initialize the arrays
p = new float[numLevels];
t = new float[numLevels];
td = new float[numLevels];
spd = new float[numLevels];
dir = new float[numLevels];
// fill the arrays
if (oneTrop) j = new int[] {index[0]};
if (!oneTrop || (oneTrop && press.getFloat(j) != pFill)) {
for (i = 0; i < numLevels; i++) {
if (!oneTrop) j[1] = i;
p[i] = press.getFloat(j) == pFill
? Float.NaN
: press.getFloat(j);
t[i] = temp.getFloat(j) == tpFill
? Float.NaN
: temp.getFloat(j);
/*
td[i] = dewpt.getFloat(j) == tdFill
? Float.NaN
: dewpt.getFloat(j);
*/
td[i] = dewpt.getFloat(j) == tdFill
? Float.NaN
: dewpointIsDepression == true
? t[i] - dewpt.getFloat(j)
: dewpt.getFloat(j);
spd[i] = speed.getFloat(j) == spdFill
? Float.NaN
: speed.getFloat(j);
dir[i] = direct.getFloat(j) == dirFill
? Float.NaN
: direct.getFloat(j);
}
sound.getRAOB().setTropopauseProfile(
RAOB.newTropopauseProfile(
pUnit, p, tUnit, t, tdUnit, td, spdUnit, spd,
dirUnit, dir));
}
}
else if (debug)
System.out.println("No tropopause data found " +
"for this station");
} catch (Exception e) {
logException ("Unable to set tropopause data for station " +
sound.getStation(), e);
}
}
}
/** create a DateTime object for the soundingob */
private DateTime getObsTime(int[] index) {
// if first time through, get some metadata
try {
if (timeUnit == null) {
timeUnit = getUnit(time);
if (timeUnit == null) timeUnit = RealType.Time.getDefaultUnit();
Attribute a = time.getAttribute("_FillValue");
if (a != null) timeFill = a.getNumericValue().doubleValue();
}
} catch (Exception ve) {
timeUnit = RealType.Time.getDefaultUnit();
timeFill = Double.NaN;
}
try {
double val = time.getDouble(index);
return
(Double.doubleToLongBits(val) ==
Double.doubleToLongBits(timeFill))
? (DateTime)null
: (timeUnit == null)
? new DateTime(val)
: new DateTime( new Real(RealType.Time, val, timeUnit));
} catch (Exception ne) {
logException ("getObsTime", ne);
}
return null;
}
protected String getDflt (String name, String dflt) {
return getDflt ("NetcdfSoundingAdapter", name, dflt);
}
/**
* Determines the names of the variables in the netCDF file that
* should be used.
*/
private void getVariables()
throws Exception {
stid = nc.get (getDflt ("stationIDVariable", "wmoStaNum"));
if (stid == null)
throw new Exception("Unable to find station id variable");
lat = nc.get(getDflt("latitudeVariable", "staLat"));
if (lat == null)
throw new Exception("Unable to find latitude variable");
lon = nc.get(getDflt("longitudeVariable", "staLon"));
if (lon == null)
throw new Exception("Unable to find longitude variable");
elev = nc.get(getDflt("stationElevVariable", "staElev"));
if (elev == null)
throw new Exception("Unable to find station elevation variable");
Attribute a = nc.getAttribute("timeVariables");
time = nc.get(
(a != null)
? a.getStringValue()
: getDflt("soundingTimeVariable", "relTime"));
if (time == null)
throw new Exception("Unable to find sounding time variable");
numMandP = nc.get(getDflt("numMandPresLevels", "numMand"));
if (numMandP != null) {
hasMandP = true;
prMandPVar = getDflt("mandPPressureVariable", "prMan");
htMandPVar = getDflt("mandPHeightVariable", "htMan");
tpMandPVar = getDflt("mandPTempVariable", "tpMan");
tdMandPVar = getDflt("mandPDewptVariable", "tdMan");
spdMandPVar = getDflt("mandPWindSpeedVariable", "wsMan");
dirMandPVar = getDflt("mandPWindDirVariable", "wdMan");
}
numMandW = nc.get(getDflt("numMandWindLevels", "numMandW"));
if (numMandW != null) {
hasMandW = true;
htMandWVar = getDflt("mandWHeightVariable", "htMandW");
spdMandWVar = getDflt("mandWWindSpeedVariable", "wsMandW");
dirMandWVar = getDflt("mandWWindDirVariable", "wdMandW");
}
numSigT = nc.get(getDflt("numSigTempLevels", "numSigT"));
if (numSigT != null) {
hasSigT = true;
prSigTVar = getDflt("sigTPressureVariable", "prSigT");
tpSigTVar = getDflt("sigTTempVariable", "tpSigT");
tdSigTVar = getDflt("sigTDewptVariable", "tdSigT");
}
numSigW = nc.get(getDflt("numSigWindLevels", "numSigW"));
if (numSigW != null) {
hasSigW = true;
htSigWVar = getDflt("sigWHeightVariable", "htSigW");
spdSigWVar = getDflt("sigWWindSpeedVariable", "wsSigW");
dirSigWVar = getDflt("sigWWindDirVariable", "wdSigW");
}
numMaxW = nc.get(getDflt("numMaxWindLevels", "numMwnd"));
if (numMaxW != null) {
hasMaxW = true;
prMaxWVar = getDflt("maxWPressureVariable", "prMaxW");
spdMaxWVar = getDflt("maxWWindSpeedVariable", "wsMaxW");
dirMaxWVar = getDflt("maxWWindDirVariable", "wdMaxW");
}
numTrop = nc.get(getDflt("numTropLevels", "numTrop"));
if (numTrop == null) {
// see if this is the old version (one trop level)
if (nc.contains(getDflt("prTropName", "prTrop"))) {
hasTrop = true;
oneTrop = true;
}
}
else {
hasTrop = true;
}
if (hasTrop) {
prTropVar = getDflt ("tropPressureVariable", "prTrop");
tpTropVar = getDflt ("tropTempVariable", "tpTrop");
tdTropVar = getDflt ("tropDewptVariable", "tdTrop");
spdTropVar = getDflt ("tropWindSpeedVariable", "wsTrop");
dirTropVar = getDflt ("tropWindDirVariable", "wdTrop");
}
// Check to see if dewpoint is stored as a depression or actual value.
dewpointIsDepression = Boolean.valueOf(getDflt("dewpointIsDepression",
"true")).booleanValue();
// See if there is a default value for missing data
try {
missingValue = Float.parseFloat(getDflt("missingValue", "99999"));
} catch (NumberFormatException excp) {
missingValue = 99999;
}
}
/** gets the units of the variable */
private Unit getUnit(Variable v) {
Unit u = null;
Attribute a = v.getAttribute("units");
if (a != null) {
try {
u = Parser.parse(a.getStringValue());
} catch (Exception e) {
u = null;
}
}
return u;
}
/** gets the fill value for the variable or if none, returns
a default value */
private float getFillValue(Variable v, float defaultValue) {
Attribute a = v.getAttribute("_FillValue");
return (a == null) ? defaultValue
: a.getNumericValue().floatValue();
}
}