/*
 * 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
     *				data 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
     *				Text 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
     *				Real 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
     *				Tuple 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
     *				Field 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
     * 			set instanceof LinearSet.
     * @return		The netCDF dimensions of set.
     */
    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 set.
     * @exception VisADException	Problem in core VisAD.
     * @exception BadFormException	set 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: set.getDimension() == 1.
     * @return		The netCDF dimension corresponding to the 1-D
     *			SampledSet.
     * @exception VisADException	Problem in core VisAD.
     * @exception BadFormException	set 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: set.getDimension()
     *			> 1.
     * @return		The netCDF dimension corresponding to the
     *			SampledSet.
     * @exception VisADException	Problem in core VisAD.
     * @exception BadFormException	set 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();
    }
}

 

Ads help maintain this website.