/*
* Copyright 1998, University Corporation for Atmospheric Research
* All Rights Reserved.
* See file LICENSE for copying and redistribution conditions.
*
* $Id: VisADAdapter.java,v 1.7 2002-10-15 18:15:15 donm Exp $
*/
package visad.data.netcdf.out;
import java.io.IOException;
import java.rmi.RemoteException;
import ucar.multiarray.Accessor;
import ucar.multiarray.IndexIterator;
import ucar.netcdf.AbstractNetcdf;
import ucar.netcdf.Dimension;
import ucar.netcdf.ProtoVariable;
import visad.Data;
import visad.Field;
import visad.Gridded1DSet;
import visad.GriddedSet;
import visad.Linear1DSet;
import visad.LinearSet;
import visad.Real;
import visad.RealTupleType;
import visad.RealType;
import visad.SampledSet;
import visad.ScalarType;
import visad.Set;
import visad.SetType;
import visad.Text;
import visad.Tuple;
import visad.UnimplementedException;
import visad.Unit;
import visad.VisADException;
import visad.data.BadFormException;
/**
* The VisADAdapter class adapts a VisAD data object to the AbstractNetcdf API.
*/
public class
VisADAdapter
extends AbstractNetcdf
{
/**
* Construct from a generic VisAD data object.
*
* @param data The VisAD data object to be adapted to a netCDF
* API
* @exception UnimplementedException Something that should be
* implemented isn't yet.
* @exception BadFormException The VisAD data object cannot be
* adapted to a netCDF API
* @exception VisADException Problem in core VisAD. Some VisAD
* object probably couldn't be created.
* @exception RemoteException Remote data access failure.
* @exception IOException Data access failure.
*/
public
VisADAdapter(Data data)
throws BadFormException, VisADException, RemoteException, IOException
{
try
{
visit(data, new TrivialAccessor(data));
}
catch (UnimplementedException e)
{
throw new BadFormException(e.getMessage());
}
}
/**
* Visit a VisAD data object.
*
* @param data The VisAD data object to be visited.
* @param outerAccessor The means for accessing the individual VisAD
* <code>data</code> objects of the enclosing
* VisAD data object.
* @exception UnimplementedException Something that should be
* implemented isn't yet.
* @exception BadFormException The VisAD data object cannot be
* adapted to a netCDF API
* @exception VisADException Problem in core VisAD.
* Probably some VisAD object couldn't be created.
* @exception RemoteException Remote data access failure.
* @exception IOException Data access failure.
*/
protected void
visit(Data data, VisADAccessor outerAccessor)
throws UnimplementedException, BadFormException, VisADException,
RemoteException, IOException
{
/*
* Watch the ordering in the following because the first match
* will be used.
*/
if (data instanceof Text)
visit((Text)data, outerAccessor);
else
if (data instanceof Real)
visit((Real)data, outerAccessor);
else
if (data instanceof Tuple)
visit((Tuple)data, outerAccessor);
else
if (data instanceof Field)
visit((Field)data, outerAccessor);
else
throw new UnimplementedException(
"VisAD data type not yet supported: " +
data.getClass().getName());
}
/**
* Visit a VisAD Text object.
*
* @param text The VisAD Text object to be visited.
* @param outerAccessor The means for accessing the individual VisAD
* <code>Text</code> objects of the enclosing
* VisAD data object.
* @exception BadFormException The VisAD data object cannot be
* adapted to a netCDF API
* @exception IOException Data access failure.
*/
protected void
visit(Text text, VisADAccessor outerAccessor)
throws BadFormException, IOException
{
/*
* Because netCDF text variables must have a "character length"
* dimension, we traverse all the strings in order to determine
* the maximum length.
*/
int charLen = 1; // gotta have at least 1 character
for (IndexIterator index =
new IndexIterator(outerAccessor.getLengths());
index.notDone();
index.incr())
{
int len = ((Text)outerAccessor.get(index.value()))
.getValue().length();
if (len > charLen)
charLen = len;
}
/*
* Define the new character dimension.
*/
String dimName = ((ScalarType)text.getType()).getName() +
"_len";
Dimension charDim = new Dimension(dimName, charLen);
putDimension(charDim);
/*
* Define the new netCDF character variable.
*/
DependentTextVar var = new DependentTextVar(text,
new TextAccessor(charDim, outerAccessor));
try
{
add(var, var);
}
catch (Exception e)
{
throw new BadFormException(e.getMessage());
}
}
/**
* Visit a VisAD Real object.
*
* @param real The VisAD Real object to be visited.
* @param outerAccessor The means for accessing the individual VisAD
* <code>Real</code> objects of the enclosing
* VisAD data object.
* @exception BadFormException The VisAD data object cannot be
* adapted to a netCDF API
* @exception VisADException Problem in core VisAD.
* Probably some VisAD object couldn't be created.
*/
protected void
visit(Real real, VisADAccessor outerAccessor)
throws BadFormException, VisADException
{
DependentRealVar var = new DependentRealVar(real,
new RealAccessor(outerAccessor));
try
{
add(var, var);
}
catch (Exception e)
{
throw new BadFormException(e.getMessage());
}
}
/**
* Visit a VisAD Tuple object.
*
* @param tuple The VisAD Tuple object to be visited.
* @param outerAccessor The means for accessing the individual VisAD
* <code>Tuple</code> objects of the enclosing
* VisAD data object.
* @exception VisADException Problem in core VisAD. Probably some
* VisAD object couldn't be created.
* @exception RemoteException Remote data access failure.
* @exception IOException Local data access failure.
*/
protected void
visit(Tuple tuple, VisADAccessor outerAccessor)
throws VisADException, RemoteException, IOException
{
int componentCount = tuple.getDimension();
for (int i = 0; i < componentCount; ++i)
visit(tuple.getComponent(i), new TupleAccessor(i, outerAccessor));
}
/**
* Define the netCDF dimensions and variables of a VisAD Field object.
*
* @param field The VisAD Field to be visited
* @param outerAccessor The means for accessing the individual VisAD
* <code>Field</code> objects of the enclosing
* VisAD data object.
* @exception UnimplementedException
* Something that should be implemented
* isn't yet.
* @exception BadFormException The VisAD data object cannot be adapted
* to a netCDF API
* @exception VisADException Problem in core VisAD. Probably some
* VisAD object couldn't be created.
* @exception RemoteException Remote data access failure.
* @exception IOException Local data access failure.
*/
protected void
visit(Field field, VisADAccessor outerAccessor)
throws RemoteException, VisADException, BadFormException,
UnimplementedException, IOException
{
Set set = field.getDomainSet();
Dimension[] dims;
if (set instanceof LinearSet)
{
/*
* The domain set is a cross-product of arithmetic
* progressions. This maps directly into the netCDF
* data model -- possibly with coordinate variables.
*/
dims = defineLinearSetDims((GriddedSet)set);
} // the sample-domain is linear
else
if (set instanceof SampledSet)
{
/*
* The domain set is not an arithmetic progression.
*/
dims = new Dimension[] {defineSampledSetDim((SampledSet)set)};
}
else
{
throw new BadFormException(
"Can't handle a " + set.getClass().getName() + " domain set");
}
/*
* Continue the definition process on the inner, VisAD data
* objects by visiting the first sample. The dimension array
* is converted to netCDF order (outermost dimension first).
*/
// System.out.println("visit(Field,...): RangeType: " +
// field.getSample(0).getType());
visit(field.getSample(0),
new FieldAccessor(reverse(dims), outerAccessor));
}
/**
* Define the netCDF dimensions of a VisAD LinearSet, including any
* necessary coordinate variables..
*
* @param set The VisAD GriddedSet to be examined, WHERE
* <code>set instanceof LinearSet</code>.
* @return The netCDF dimensions of <code>set</code>.
*/
protected Dimension[]
defineLinearSetDims(GriddedSet set)
throws VisADException, BadFormException
{
int rank = set.getDimension();
Dimension[] dims = new Dimension[rank];
RealTupleType domainType = ((SetType)set.getType()).getDomain();
Unit[] units = set.getSetUnits();
/*
* Define any necessary coordinate-variables.
*/
for (int idim = 0; idim < rank; ++idim)
{
Linear1DSet linear1DSet =
((LinearSet)set).getLinear1DComponent(idim);
int length = linear1DSet.getLength(0);
String name =
((RealType)domainType.getComponent(idim)).getName();
dims[idim] = new Dimension(name, length);
if (linear1DSet.getFirst() != 0.0 ||
linear1DSet.getStep() != 1.0)
{
/*
* The domain sampling has associated coordinate
* values; therefore, we define a corresponding
* netCDF coordinate-variable.
*/
CoordVar var =
new CoordVar(name, dims[idim], units[idim], linear1DSet);
try
{
add(var, var);
}
catch (Exception e)
{
throw new BadFormException(e.getMessage());
}
}
} // sample-domain dimension loop
return dims;
}
/**
* Define the netCDF dimensions and variables of a VisAD SampledSet.
*
* @param set The VisAD SampledSet to be examined.
* @return The netCDF dimension of <code>set</code>.
* @exception VisADException Problem in core VisAD.
* @exception BadFormException <code>set</code> cannot be represented
* in a netCDF dataset.
**/
protected Dimension
defineSampledSetDim(SampledSet set)
throws VisADException, BadFormException
{
int rank = set.getManifoldDimension();
return rank == 1
? define1DDim(set)
: defineNDDim(set);
}
/**
* Define the netCDF dimension of a 1-D SampledSet. This dimension will
* have an associated, netCDF coordinate variable.
*
* @param set The set to have a netCDF dimension defined for it.
* Precondition: <code>set.getDimension() == 1</code>.
* @return The netCDF dimension corresponding to the 1-D
* SampledSet.
* @exception VisADException Problem in core VisAD.
* @exception BadFormException <code>set</code> cannot be represented
* in a netCDF dataset.
*/
protected Dimension
define1DDim(SampledSet set)
throws VisADException, BadFormException
{
RealTupleType domainType = ((SetType)set.getType()).getDomain();
String name =
((RealType)domainType.getComponent(0)).getName();
Dimension dim = new Dimension(name, set.getLength());
Unit[] units = set.getSetUnits();
if (!(set instanceof Gridded1DSet))
throw new BadFormException("Domain set not Gridded1DSet");
CoordVar var =
new CoordVar(name, dim, units[0], (Gridded1DSet)set);
try
{
add(var, var);
}
catch (Exception e)
{
throw new BadFormException(e.getMessage());
}
return dim;
}
/**
* Define the netCDF dimension of a multi-dimensional SampledSet.
* This will be an "index" dimension with associated netCDF variables
* that represent the independent coordinates of the domain set.
*
* @param set The VisAD SampledSet to be examined and have
* a corresponding netCDF "index" dimension created
* together with netCDF variables for the independent
* variables. Precondition: <code>set.getDimension()
* > 1</code>.
* @return The netCDF dimension corresponding to the
* SampledSet.
* @exception VisADException Problem in core VisAD.
* @exception BadFormException <code>set</code> cannot be represented
* in a netCDF dataset.
*/
protected Dimension
defineNDDim(SampledSet set)
throws VisADException, BadFormException
{
Dimension dim;
RealTupleType domainType = ((SetType)set.getType()).getDomain();
int rank = domainType.getDimension();
Unit[] units = set.getSetUnits();
String[] names = new String[rank];
/*
* Get the names.
*/
for (int idim = 0; idim < rank; ++idim)
names[idim] = ((RealType)domainType.getComponent(idim)).getName();
/*
* Define the "index" dimension.
*/
{
int len = names[0].length();
for (int idim = 1; idim < rank; ++idim)
len += 1 + names[idim].length();
len += 4;
StringBuffer name = new StringBuffer(len);
name.append(names[0]);
for (int idim = 1; idim < rank; ++idim)
{
name.append("_");
name.append(names[idim]);
}
name.append("_ndx");
dim = new Dimension(name.toString(), set.getLength());
}
/*
* Define the independent variables.
*/
for (int idim = 0; idim < rank; ++idim)
{
IndependentVar var =
new IndependentVar(names[idim], dim, units[idim],
(SampledSet)set, idim);
try
{
add(var, var);
}
catch (Exception e)
{
throw new BadFormException(e.getMessage());
}
}
return dim;
}
/**
* Reverse the dimensions in a 1-D array.
*/
protected Dimension[]
reverse(Dimension[] inDims)
{
Dimension[] outDims = new Dimension[inDims.length];
for (int i = 0; i < inDims.length; ++i)
outDims[i] = inDims[inDims.length - 1 - i];
return outDims;
}
/**
* Return a MultiArray Accessor for a variable.
*
* This method is part of the AbstractNetcdf class and should never
* be called -- so it always throws an error.
*/
public Accessor
ioFactory(ProtoVariable protoVar)
{
throw new UnsupportedOperationException();
}
}