//
// FieldImpl.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 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;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Vector;
/**
FieldImpl is the VisAD class for finite samplings of functions
from R^n to a range type, where n>0. The DomainSet, DomainUnits
and DomainCoordinateSystem variables of FieldImpl are immutable.<P>
A FieldImpl domain type may be either a RealType (for a function with
domain = R) or a RealTupleType (for a function with domain = R^n
for n > 0).<P>
*/
public class FieldImpl extends FunctionImpl implements Field {
private static final long serialVersionUID = 1L;
/** the sampling of the function domain R^n */
Set DomainSet;
/** this is DomainSet.DomainCoordinateSystem */
CoordinateSystem DomainCoordinateSystem;
/** this is DomainSet.SetUnits */
Unit[] DomainUnits;
/** the number of samples */
int Length;
/** the array of function values */
//jeffm: Change the name of Range to MyRange
//so methods that use Range can simply call:
//Data[]Range = getRange ();
private Data[] MyRange; // won't be null though elements might be
// This is used to synchronize access to the Range (which might be null)
// use VisADRay since it is Serializable and small
private VisADRay RangeLock = new VisADRay();
private boolean MissingFlag;
/** construct a FieldImpl from type;
use default Set of FunctionType domain;
initial values are missing */
public FieldImpl(FunctionType type) throws VisADException {
this(type, null);
}
/**
* Constructs from the type of function and a set of domain points.
*
* @param type The type of function.
* @param set The set of domain points. Defines the units
* and any coordinate system transformation
* for the domain of the funciton. May be
* <code>null</code>, in which case the default
* domain set ({@link FunctionType#getDomain()}) is
* used. May <em>not</em> be {@link FloatSet} or
* {@link DoubleSet}. If non-<code>null</code>,
* then must be compatible with the domain of the
* FunctionType.
* @throws CoordinateSystemException
* if the {@link CoordinateSystem} of the
* domain set is <code>null</code> but the
* {@link CoordinateSystem} of the domain of
* the FunctionType} is not; or if both {@link
* CoordinateSystem}s are non-<code>null</code>
* and do not have the same reference {@link
* RealTupleType}.
* @throws VisADException if a VisAD failure occurs.
*/
public FieldImpl(FunctionType type, Set set) throws VisADException {
//Turn around and call the other ctor - the true says to go ahead
//and create the Range array
this (type, set, true);
}
/**
* Trusted constructor for subclasses that don't need to have the
* Range array instantiated (i.e., FlatField).
*
* @param type The type of function.
* @param set The set of domain points. Defines the units
* and any coordinate system transformation
* for the domain of the funciton. May be
* <code>null</code>, in which case the default
* domain set ({@link FunctionType#getDomain()}) is
* used. May <em>not</em> be {@link FloatSet} or
* {@link DoubleSet}. If non-<code>null</code>,
* then must be compatible with the domain of the
* FunctionType.
* @param createRangeArray If true then the Range array is allocated.
* @throws CoordinateSystemException
* if the {@link CoordinateSystem} of the
* domain set is <code>null</code> but the
* {@link CoordinateSystem} of the domain of
* the FunctionType} is not; or if both {@link
* CoordinateSystem}s are non-<code>null</code>
* and do not have the same reference {@link
* RealTupleType}.
* @throws VisADException if a VisAD failure occurs.
*/
protected FieldImpl(FunctionType type, Set set, boolean createRangeArray)
throws VisADException {
super(type);
RealTupleType DomainType = type.getDomain();
if (set == null) set = DomainType.getDefaultSet();
if (set == null) {
throw new SetException("FieldImpl: set cannot be null");
}
if (set instanceof DoubleSet || set instanceof FloatSet) {
throw new SetException("FieldImpl: set may not be DoubleSet " +
"or FloatSet");
}
if (DomainType.getDimension() != set.getDimension()) {
throw new SetException("FieldImpl: set dimension " + set.getDimension() +
" and type dimension " +
DomainType.getDimension() + " don't match");
}
// force DomainSet Type to match DomainType
if (DomainType.equals(((SetType) set.getType()).getDomain())) {
DomainSet = set;
}
else {
DomainSet = (Set) set.cloneButType(new SetType(DomainType));
}
DomainCoordinateSystem = DomainSet.getCoordinateSystem();
CoordinateSystem domTypeCs = DomainType.getCoordinateSystem();
if (domTypeCs == null
? (DomainCoordinateSystem != null)
: (DomainCoordinateSystem != null && !domTypeCs.getReference().equals(
DomainCoordinateSystem.getReference()))) {
throw new CoordinateSystemException(domTypeCs, DomainCoordinateSystem);
}
DomainUnits = DomainSet.getSetUnits();
Length = DomainSet.getLength();
if (createRangeArray) {
MyRange = new Data[Length];
}
MissingFlag = true;
}
/**
This creates (if it has not been created already) and returns the MyRange data member
**/
private Data[] getRange () {
synchronized (RangeLock) {
if (MyRange == null) {
MyRange = new Data[getLength()];
}
}
return MyRange;
}
/**
* Set the range samples of the function; the order of range samples
* must be the same as the order of domain indices in the DomainSet;
* copy range objects if copy is true;
* @param range The range values
* @param copy should the range values be copied
*/
public void setSamples(Data[] range, boolean copy)
throws VisADException, RemoteException {
setSamples(range, copy, true);
}
/**
* Set the range samples of the function; the order of range samples
* must be the same as the order of domain indices in the DomainSet;
* copy range objects if copy is true;
* should use same MathType object in each Data object in range array
* @param range The range values
* @param copy should the range values be copied
* @param checkAllRangeTypes If true then ensure that the MathType of
* each element in the range matches the type
* of this field. If false then only check the
* first range element. This is the "trust
* the calling method" flag. If you pass in false
* and there are elements in the range whose type
* does not match the type of this field then
* this may result in hard-to-track-down bugs.
*/
public void setSamples(Data[] range, boolean copy, boolean checkAllRangeTypes)
throws VisADException, RemoteException {
if (range == null) {
MyRange = null;
MissingFlag = true;
return;
}
if (range.length != getLength()) {
throw new FieldException("FieldImpl.setSamples: bad array length");
}
Data[]Range = getRange ();
synchronized (RangeLock) {
MissingFlag = false;
MathType t = ((FunctionType) Type).getRange();
for (int i=0; i<getLength(); i++) {
if (range[i] != null) {
if(i==0 || checkAllRangeTypes) {
if(!t.equals(range[i].getType())) {
throw new TypeException("FieldImpl.setSamples: sample#" + i +
" type " + range[i].getType() +
" doesn't match field type " + t);
}
}
if (copy) Range[i] = (Data) range[i].dataClone();
else Range[i] = range[i];
}
else Range[i] = null;
}
for (int i=0; i<getLength(); i++) {
if (Range[i] instanceof DataImpl) {
((DataImpl) Range[i]).setParent(this);
}
}
}
notifyReferences();
}
/**
* <p>Returns the domain-set of this instance. The actual set is returned:
* it is not a copy or a clone.</p>
*
* <p> Note that it is possible to simultaneously modify the domain-set of
* both this instance and of a clone by modifying the values in the array
* returned by invoking <code>getSamples(false)</code> on the domain-set of
* either this instance or the clone. Don't do this unless you enjoy
* debugging.</p>
*
* @return The actual domain-set of this instance.
*/
public Set getDomainSet() {
return DomainSet;
}
/** get number of samples */
public int getLength() {
return Length;
}
/**
* Returns the units of the values in the domain set. The units may differ
* from the default units of the underlying MathType of the domain, but will
* be convertible with them.
* @return The units of the values in the domain set.
*/
public Unit[] getDomainUnits() {
return DomainUnits;
}
public CoordinateSystem getDomainCoordinateSystem() {
return DomainCoordinateSystem;
}
/** get range values for Text components; the return array is dimensioned
double[number_of_range_components][number_of_range_samples] */
public String[][] getStringValues()
throws VisADException, RemoteException {
TextType[] textComponents = ((FunctionType) Type).getTextComponents();
if (textComponents == null) return null;
int[] textIndices = ((FunctionType) Type).getTextIndices();
int n = textComponents.length;
int len = getLength();
String[][] values = new String[n][len];
if (isMissing()) {
for (int k=0; k<n; k++) {
for (int i=0; i<len; i++) values[k][i] = "";
}
return values;
}
MathType RangeType = ((FunctionType) Type).getRange();
synchronized (RangeLock) {
for (int i=0; i<len; i++) {
Data range = (MyRange==null?null:MyRange[i]);
if (range == null || range.isMissing()) {
for (int k=0; k<n; k++) values[k][i] = "";
}
else {
if (RangeType instanceof TextType) {
values[0][i] = ((Text) range).getValue();
}
else if (RangeType instanceof TupleType) {
for (int k=0; k<n; k++) {
Text t = (Text) ((TupleIface) range).getComponent(textIndices[k]);
values[k][i] = t.getValue();
}
}
}
} // end for (int i=0; i<len; i++)
}
return values;
}
public float[][] getFloats()
throws VisADException, RemoteException {
return getFloats(true);
}
/** get range values for 'Flat' components in their default range
Units (as defined by the range of this FieldImpl's
FunctionType); the return array is dimensioned
float[number_of_range_components][number_of_range_samples];
copy is ignored for FieldImpl */
public float[][] getFloats(boolean copy)
throws VisADException, RemoteException {
return Set.doubleToFloat(getValues(copy));
}
public double[][] getValues()
throws VisADException, RemoteException {
return getValues(true);
}
/** get range values for 'Flat' components in their default range
Units (as defined by the range of this FieldImpl's
FunctionType); the return array is dimensioned
double[number_of_range_components][number_of_range_samples];
copy is ignored for FieldImpl */
public double[][] getValues(boolean copy)
throws VisADException, RemoteException {
RealType[] realComponents = ((FunctionType) Type).getRealComponents();
if (realComponents == null) return null;
int n = realComponents.length;
Unit[] units = getDefaultRangeUnits();
int len = getLength();
double[][] values = new double[n][len];
if (isMissing()) {
for (int k=0; k<n; k++) {
for (int i=0; i<len; i++) values[k][i] = Double.NaN;
}
return values;
}
MathType RangeType = ((FunctionType) Type).getRange();
synchronized (RangeLock) {
for (int i=0; i<len; i++) {
Data range = (MyRange == null? null: MyRange[i]);
if (range == null || range.isMissing()) {
for (int k=0; k<n; k++) values[k][i] = Double.NaN;
}
else {
if (RangeType instanceof RealType) {
values[0][i] = ((Real) range).getValue(units[0]);
}
else if (RangeType instanceof TupleType) {
int k = 0;
for (int j=0; j<((TupleType) RangeType).getDimension(); j++) {
MathType component_type = ((TupleType) RangeType).getComponent(j);
Data component = ((TupleIface) range).getComponent(j);
if (component_type instanceof RealType) {
values[k][i] = ((Real) component).getValue(units[k]);
k++;
}
else if (component_type instanceof RealTupleType) {
for (int m=0; m<((TupleType) component_type).getDimension(); m++) {
Data comp_comp = ((TupleIface) component).getComponent(m);
values[k][i] = ((Real) comp_comp).getValue(units[k]);
k++;
}
}
}
}
}
} // end for (int i=0; i<len; i++)
}
return values;
}
/** set range array as range values of this FieldImpl;
this must have a Flat range; the array is dimensioned
float[number_of_range_components][number_of_range_samples];
the order of range values must be the same as the order of domain
indices in the DomainSet */
public void setSamples(double[][] range)
throws VisADException, RemoteException {
RealType[] realComponents = ((FunctionType) Type).getRealComponents();
if (!((FunctionType) Type).getFlat()) {
throw new FieldException("FieldImpl.setSamples: not Flat range");
}
if (realComponents == null) {
throw new FieldException("FieldImpl.setSamples: no Real components");
}
int n = realComponents.length;
int len = getLength();
if (range == null || range.length != n) {
throw new FieldException("FieldImpl.setSamples: bad tuple length");
}
if (range[0] == null || range[0].length != len) {
throw new FieldException("FieldImpl.setSamples: bad array length");
}
Unit[] units = getDefaultRangeUnits();
MathType RangeType = ((FunctionType) Type).getRange();
synchronized (RangeLock) {
MissingFlag = false;
Data[]Range = getRange ();
if (RangeType instanceof RealType) {
for (int i=0; i<len; i++) {
Range[i] = new Real((RealType) RangeType, range[0][i], units[0]);
}
}
else if (RangeType instanceof RealTupleType) {
int ntup = ((RealTupleType) RangeType).getDimension();
Real[] reals = new Real[ntup];
for (int i=0; i<len; i++) {
for (int j=0; j<ntup; j++) {
RealType type = (RealType)
((RealTupleType) RangeType).getComponent(j);
reals[j] = new Real(type, range[j][i], units[j]);
}
Range[i] = new RealTuple(reals);
}
}
else if (RangeType instanceof TupleType) {
int ntup = ((TupleType) RangeType).getDimension();
Data[] data = new Real[ntup];
MathType[] types = new MathType[ntup];
for (int j=0; j<ntup; j++) {
types[j] = ((TupleType) RangeType).getComponent(j);
}
for (int i=0; i<len; i++) {
int k = 0;
for (int j=0; j<ntup; j++) {
if (types[j] instanceof RealType) {
data[j] = new Real((RealType) types[j], range[k][i], units[k]);
k++;
}
else { // types[j] instanceof RealTupleType
int mtup = ((RealTupleType) types[j]).getDimension();
Real[] reals = new Real[mtup];
for (int m=0; m<mtup; m++) {
RealType type = (RealType)
((RealTupleType) types[j]).getComponent(m);
reals[m] = new Real(type, range[k][i], units[k]);
k++;
}
data[j] = new RealTuple(reals);
}
} // end for (int j=0; j<ntup; j++)
Range[i] = new Tuple(data);
} // end for (int i=0; i<len; i++)
}
}
return;
}
/** set range array as range values of this FieldImpl;
this must have a Flat range; the array is dimensioned
float[number_of_range_components][number_of_range_samples];
the order of range values must be the same as the order of domain
indices in the DomainSet */
public void setSamples(float[][] range)
throws VisADException, RemoteException {
setSamples(Set.floatToDouble(range));
}
/** return array of Units associated with each RealType
component of range; these may differ from default
Units of range RealTypes, but must be convertable;
the second index enumerates samples since Units may
differ between samples */
public Unit[][] getRangeUnits()
throws VisADException, RemoteException {
RealType[] realComponents = ((FunctionType) Type).getRealComponents();
if (realComponents == null) return null;
int n = realComponents.length;
Unit[][] units = new Unit[n][getLength()];
Unit[] default_units = getDefaultRangeUnits();
MathType RangeType = ((FunctionType) Type).getRange();
for (int i=0; i<getLength(); i++) {
Data range = (MyRange==null?null:MyRange[i]);
if (range == null || range.isMissing()) {
for (int k=0; k<n; k++) units[k][i] = default_units[k];
}
else {
if (RangeType instanceof RealType) {
units[0][i] = ((Real) range).getUnit();
}
else if (RangeType instanceof TupleType) {
int k = 0;
for (int j=0; j<((TupleType) RangeType).getDimension(); j++) {
MathType component_type = ((TupleType) RangeType).getComponent(i);
Data component = ((TupleIface) range).getComponent(j);
if (component_type instanceof RealType) {
units[k][i] = ((Real) component).getUnit();
k++;
}
else if (component_type instanceof RealTupleType) {
for (int m=0; m<((TupleType) component_type).getDimension(); m++) {
Data comp_comp = ((TupleIface) component).getComponent(m);
units[k][i] = ((Real) comp_comp).getUnit();
k++;
}
}
}
}
}
}
return units;
}
/**
* Get range CoordinateSystem for 'RealTuple' range;
* second index enumerates samples.
* @return range CoordinateSystem assuming range type is
* a RealTupleType (throws a TypeException if its not);
* this may differ from default CoordinateSystem of
* range RealTupleType, but must be convertable;
* the index enumerates samples since Units may
* differ between samples
*/
public CoordinateSystem[] getRangeCoordinateSystem()
throws VisADException, RemoteException {
MathType RangeType = ((FunctionType) Type).getRange();
if (!(RangeType instanceof RealTupleType)) {
throw new TypeException("FieldImpl.getRangeCoordinateSystem: " +
"Range is not RealTupleType");
}
CoordinateSystem[] cs = new CoordinateSystem[getLength()];
CoordinateSystem default_cs =
((RealTupleType) RangeType).getCoordinateSystem();
for (int i=0; i<getLength(); i++) {
Data range = (MyRange==null?null:MyRange[i]);
if (range == null || range.isMissing()) {
cs[i] = default_cs;
}
else {
cs[i] = ((RealTuple) range).getCoordinateSystem();
}
}
return cs;
}
/** get range CoordinateSystem for 'RealTuple' components;
second index enumerates samples */
public CoordinateSystem[] getRangeCoordinateSystem(int component)
throws VisADException, RemoteException {
MathType RangeType = ((FunctionType) Type).getRange();
if ( (!(RangeType instanceof TupleType)) ||
(RangeType instanceof RealTupleType) ) {
throw new TypeException("FieldImpl.getRangeCoordinateSystem: " +
"Range must be TupleType but not RealTupleType");
}
MathType component_type =
((TupleType) RangeType).getComponent(component);
if (!(component_type instanceof RealTupleType)) {
throw new TypeException("FieldImpl.getRangeCoordinateSystem: " +
"selected Range component must be RealTupleType");
}
CoordinateSystem[] cs = new CoordinateSystem[getLength()];
CoordinateSystem default_cs =
((RealTupleType) component_type).getCoordinateSystem();
for (int i=0; i<getLength(); i++) {
Data range = (MyRange==null?null:MyRange[i]);
if (range == null || range.isMissing()) {
cs[i] = default_cs;
}
else {
Data comp = ((TupleIface) range).getComponent(component);
if (comp == null || comp.isMissing()) {
cs[i] = default_cs;
}
else {
cs[i] = ((RealTuple) comp).getCoordinateSystem();
}
}
}
return cs;
}
/** get default range Unit-s for 'Flat' components */
public Unit[] getDefaultRangeUnits() {
RealType[] realComponents = ((FunctionType) Type).getRealComponents();
if (realComponents == null) return null;
int n = realComponents.length;
Unit[] units = new Unit[n];
for (int i=0; i<n; i++) {
units[i] = realComponents[i].getDefaultUnit();
}
return units;
}
/**
* <p>Get the range value at the index-th sample. The actual range value
* is returned -- not a copy.</p>
*
* <p>This implementation uses {@link #getSample(int, boolean)}.</p>
*
* @param index index of requested range sample
* @return range value at sample index
*/
public Data getSample(int index)
throws VisADException, RemoteException {
return getSample(index, false);
}
/**
* Get the metadata for the range value at the index-th sample. If the range
* value is also requested, then the actual range value is returned -- not a
* copy.</p>
*
* @param index index of requested range sample
* @param metadataOnly <tt>true</tt> if only the metadata is needed,
* <tt>false</ff> if both metadata and data are
* desired.
*/
public Data getSample(int index, boolean metadataOnly)
throws VisADException, RemoteException {
synchronized (RangeLock) {
if (MyRange == null || isMissing() || index < 0 || index >= getLength() || MyRange[index] == null) {
return ((FunctionType) Type).getRange().missingData();
}
else return MyRange[index];
}
}
/** set the range value at the sample nearest to domain */
public void setSample(RealTuple domain, Data range, boolean copy)
throws VisADException, RemoteException {
if (getDomainSet() == null) {
throw new FieldException("FieldImpl.setSample: DomainSet undefined");
}
// WLH 9 Dec 99
// if (!((FunctionType) Type).getDomain().equalsExceptName(domain.getType())) {
if (!((FunctionType) Type).getDomain().equals(domain.getType())) {
throw new TypeException("FieldImpl.setSample: bad domain type");
}
int dimension = getDomainSet().getDimension();
double[][] vals = new double[dimension][1];
for (int j=0; j<dimension; j++) {
vals[j][0] = ((Real) ((RealTuple) domain).getComponent(j)).getValue();
}
// always use simple resampling for set
int[] indices = getDomainSet().doubleToIndex(vals);
setSample(indices[0], range, copy);
}
public void setSample(RealTuple domain, Data range)
throws VisADException, RemoteException {
setSample(domain, range, true);
}
/**
* Set the range value at the index-th sample; makes a local copy
* @param index index in domain
* @param range sample at that index
*/
public void setSample(int index, Data range)
throws VisADException, RemoteException {
setSample(index, range, true);
}
/**
* Set the range value at the index-th sample
* @param index index in domain
* @param range sample at that index
* @param copy true to make a copy
*/
public void setSample(int index, Data range, boolean copy)
throws VisADException, RemoteException {
setSample(index, range, copy, true);
}
/**
* Set the range value at the index-th sample
* @param index index in domain
* @param range sample at that index
* @param copy true to make a copy
* @param checkRangeType setting to false will not check to make
* sure that the sample MathType is the same as
* this FieldImpl's range. This saves on time
* at the expense of accuracy. Use this only
* if you like shooting yourself in the foot.
*/
public void setSample(int index, Data range, boolean copy, boolean checkRangeType)
throws VisADException, RemoteException {
if (getDomainSet() == null) {
throw new FieldException("FieldImpl.setSample: DomainSet undefined");
}
if (range != null && checkRangeType &&
!((FunctionType) Type).getRange().equals(range.getType())) {
throw new TypeException("FieldImpl.setSample: bad range type");
}
if (index >= 0 && index < getLength()) {
Data[]Range = getRange ();
synchronized (RangeLock) {
MissingFlag = false;
if (range != null) {
if (copy) {
Range[index] = (Data) range.dataClone();
}
else {
Range[index] = range;
}
if (Range[index] instanceof DataImpl) {
((DataImpl) Range[index]).setParent(this);
}
}
else {
Range[index] = null;
}
}
}
notifyReferences();
}
/** test whether Field value is missing */
public boolean isMissing() {
synchronized (RangeLock) {
return MissingFlag;
}
}
/** return new Field with value 'this op data';
test for various relations between types of this and data */
/*- TDR May 1998
public Data binary(Data data, int op, int sampling_mode, int error_mode)
throws VisADException, RemoteException {
*/
public Data binary(Data data, int op, MathType new_type,
int sampling_mode, int error_mode)
throws VisADException, RemoteException {
boolean field_flag; // true if this and data have same type
if ( new_type == null ) {
throw new TypeException("binary: new_type may not be null" );
}
if (Type.equalsExceptName(data.getType())) {
/*- TDR May 1998 */
if ( !Type.equalsExceptName( new_type )) {
throw new TypeException("binary: new_type doesn't match return type");
}
/*- end */
// type of this and data match, so normal Field operation
field_flag = true;
if (((Field) data).isFlatField()) {
// force (data instanceof FlatField) to be true
data = data.local();
// this and data have same type, but data is Flat and this is not
data = ((FlatField) data).convertToField();
}
}
else if (data instanceof Real ||
((FunctionType) Type).getRange().equalsExceptName(data.getType())) {
// data is real or matches range type of this
field_flag = false;
/*- TDR May 1998 */
if ( !Type.equalsExceptName( new_type )) {
throw new TypeException("binary: new_type doesn't match return type");
}
/*- end */
}
else if (data instanceof Field &&
((FunctionType) data.getType()).getRange().equalsExceptName(Type)) {
/*- TDR May 1998 */
if ( !((FunctionType) data.getType()).getRange().equalsExceptName(new_type)) {
throw new TypeException("binary: new_type doesn't match return type");
}
/*- end */
// this matches range type of data
// note invertOp to reverse order of operands
/*- TDR May 1998
return data.binary(this, invertOp(op), sampling_mode, error_mode);
*/
return data.binary(this, invertOp(op), new_type, sampling_mode, error_mode);
}
else {
throw new TypeException("FieldImpl.binary: types don't match");
}
// create (initially missing) Field for return
Field new_field = new FieldImpl((FunctionType) new_type, getDomainSet());
if (isMissing() || data.isMissing()) return new_field;
Data[] range = new Data[getLength()];
/*- TDR May 1998 */
MathType m_type = ((FunctionType)new_type).getRange();
if (field_flag) {
// resample data if needed
data = ((Field) data).resample(getDomainSet(), sampling_mode, error_mode);
// apply operation to each range object
for (int i=0; i<getLength(); i++) {
synchronized (RangeLock) {
range[i] = ((MyRange==null||MyRange[i] == null)) ? null :
/*- TDR May 1998
Range[i].binary(((Field) data).getSample(i), op,
sampling_mode, error_mode);
*/
MyRange[i].binary(((Field) data).getSample(i), op, m_type,
sampling_mode, error_mode);
}
}
}
else { // !field_flag
for (int i=0; i<getLength(); i++) {
synchronized (RangeLock) {
range[i] = ((MyRange==null||MyRange[i] == null)) ? null :
/*- TDR May 1998
MyRange[i].binary(data, op, sampling_mode, error_mode);
*/
MyRange[i].binary(data, op, m_type, sampling_mode, error_mode);
}
}
}
new_field.setSamples(range, false);
return new_field;
}
/** return new Field with value 'op this' */
/*- TDR July 1998
public Data unary(int op, int sampling_mode, int error_mode)
throws VisADException, RemoteException {
*/
public Data unary(int op, MathType new_type, int sampling_mode,
int error_mode )
throws VisADException, RemoteException {
if ( new_type == null ) {
throw new TypeException("unary: new_type may not be null");
}
if ( !Type.equalsExceptName(new_type)) {
throw new TypeException("unary: new_type doesn't match return type");
}
MathType m_type = ((FunctionType)new_type).getRange();
// create (initially missing) Field for return
/* WLH 17 Jan 2000
Field new_field = new FieldImpl((FunctionType) Type, getDomainSet());
*/
/* WLH 3 April 2003
Field new_field = new FieldImpl((FunctionType) new_type, getDomainSet());
*/
RealTupleType d_type = ((FunctionType)new_type).getDomain();
Set new_set = null;
if (!d_type.equals( ((FunctionType) getType()).getDomain() )) {
new_set = (Set) getDomainSet().cloneButType(d_type);
}
else {
new_set = getDomainSet();
}
Field new_field = new FieldImpl((FunctionType) new_type, new_set);
if (isMissing()) return new_field;
Data[] range = new Data[getLength()];
// apply operation to each range object
for (int i=0; i<getLength(); i++) {
synchronized (RangeLock) {
range[i] = ((MyRange==null||MyRange[i] == null)) ? null :
MyRange[i].unary(op, m_type, sampling_mode, error_mode);
}
}
new_field.setSamples(range, false);
return new_field;
}
/**
* Resample all elements of the fields array to the domain
* set of fields[0], then return a Field whose range samples
* are Tuples merging the corresponding range samples from
* each element of fields; if the range of fields[i] is a
* Tuple without a RangeCoordinateSystem, then each Tuple
* component of a range sample of fields[i] becomes a
* Tuple component of a range sample of the result -
* otherwise a range sample of fields[i] becomes a Tuple
* component of a range sample of the result; this assumes
* all elements of the fields array have the same domain
* dimension; use default sampling_mode (Data.NEAREST_NEIGHBOR)
* and default error_mode (Data.NO_ERRORS)
*
* @param fields fields to combine
* @return combined fields
*/
public static Field combine( Field[] fields )
throws VisADException, RemoteException
{
return combine( fields, Data.NEAREST_NEIGHBOR, Data.NO_ERRORS, true);
}
/**
* Resample all elements of the fields array to the domain
* set of fields[0], then return a Field whose range samples
* are Tuples merging the corresponding range samples from
* each element of fields. If <code>flatten</code> is true and
* if the range of fields[i] is a
* Tuple without a RangeCoordinateSystem, then each Tuple
* component of a range sample of fields[i] becomes a
* Tuple component of a range sample of the result -
* otherwise a range sample of fields[i] becomes a Tuple
* component of a range sample of the result; this assumes
* all elements of the fields array have the same domain
* dimension; use default sampling_mode (Data.NEAREST_NEIGHBOR)
* and default error_mode (Data.NO_ERRORS)
*
* @param fields fields to combine
* @param flatten true to flatten range tuples with no CoordinateSystem
* @return combined fields
*/
public static Field combine( Field[] fields, boolean flatten )
throws VisADException, RemoteException
{
return combine( fields, Data.NEAREST_NEIGHBOR, Data.NO_ERRORS, flatten );
}
/** resample all elements of the fields array to the domain
set of fields[0], then return a Field whose range samples
are Tuples merging the corresponding range samples from
each element of fields; if the range of fields[i] is a
Tuple without a RangeCoordinateSystem, then each Tuple
component of a range sample of fields[i] becomes a
Tuple component of a range sample of the result -
otherwise a range sample of fields[i] becomes a Tuple
component of a range sample of the result; this assumes
all elements of the fields array have the same domain
dimension */
public static Field combine( Field[] fields, int sampling_mode, int error_mode )
throws VisADException, RemoteException
{
return combine( fields, sampling_mode, error_mode, true);
}
/**
* Resample all elements of the fields array to the domain
* set of fields[0], then return a Field whose range samples
* are Tuples merging the corresponding range samples from
* each element of fields. If <code>flatten</code> is true and
* if the range of fields[i] is a
* Tuple without a RangeCoordinateSystem, then each Tuple
* component of a range sample of fields[i] becomes a
* Tuple component of a range sample of the result -
* otherwise a range sample of fields[i] becomes a Tuple
* component of a range sample of the result; this assumes
* all elements of the fields array have the same domain
* dimension.
*
* @param fields fields to combine
* @param sampling_mode sampling mode to use (e.g., Data.NEAREST_NEIGHBOR)
* @param error_mode error mode to use (e.g., Data.NO_ERRORS)
* @param flatten true to flatten range tuples with no CoordinateSystem
*
* @return combined fields
*/
public static Field combine( Field[] fields, int sampling_mode, int error_mode , boolean flatten)
throws VisADException, RemoteException
{
return combine(fields, sampling_mode, error_mode, flatten, true);
}
/**
* Resample all elements of the fields array to the domain
* set of fields[0], then return a Field whose range samples
* are Tuples merging the corresponding range samples from
* each element of fields. If <code>flatten</code> is true and
* if the range of fields[i] is a
* Tuple without a RangeCoordinateSystem, then each Tuple
* component of a range sample of fields[i] becomes a
* Tuple component of a range sample of the result -
* otherwise a range sample of fields[i] becomes a Tuple
* component of a range sample of the result; this assumes
* all elements of the fields array have the same domain
* dimension.
*
* @param fields fields to combine
* @param sampling_mode sampling mode to use (e.g., Data.NEAREST_NEIGHBOR)
* @param error_mode error mode to use (e.g., Data.NO_ERRORS)
* @param flatten true to flatten range tuples with no CoordinateSystem
* @param copy true to copy the values from the original fields
*
* @return combined fields
*/
public static Field combine( Field[] fields, int sampling_mode, int error_mode , boolean flatten, boolean copy)
throws VisADException, RemoteException
{
visad.util.Trace.call1("combine, copy = " + copy);
int ii, jj, kk, n_fields;
int domainDim = 0; //- domain dimension of field_0.
Set domainSet_0; //- domain set of field_0.
RealTupleType domainType_0; //- domain type of field_0.
int n_samples_0; //- number of samples in field_0.
Field new_field; //- return field.
boolean allFlat = true; //- all fields in array are FlatFields.
Field field_0 = fields[0]; //- first field in array, "this".
FunctionType new_type; //- type of result.
n_fields = fields.length;
MathType[] fieldRange_s = new MathType[ n_fields ];
MathType[][] rangeComp_s = new MathType[ n_fields ][];
FunctionType[] fieldType_s = new FunctionType[ n_fields ];
MathType new_range, range;
MathType m_type;
MathType fieldRange;
FlatField f_field;
float[][] valuesF = null;
float[][] new_valuesF = null;
double[][] valuesD = null;
double[][] new_valuesD = null;
int n_comps;
int n_dims;
int length;
int cnt = 0;
n_fields = fields.length;
n_comps = 0;
for ( ii = 0; ii < n_fields; ii++ )
{
if ( ii == 0 )
{
domainDim = field_0.getDomainDimension();
}
else if ( domainDim != fields[ii].getDomainDimension() )
{
throw new VisADException( "FieldImpl.combine: domain dimensions of input"+
"fields must match" );
}
if ( !(fields[ii].isFlatField()) )
{
allFlat = false;
}
fieldType_s[ii] = (FunctionType) fields[ii].getType();
fieldRange_s[ii] = ((FunctionType)fields[ii].getType()).getRange();
range = fieldRange_s[ii];
if ( range instanceof RealType )
{
rangeComp_s[ii] = new MathType[ 1 ];
rangeComp_s[ii][0] = range;
n_comps++;
}
else if ( range instanceof RealTupleType )
{
rangeComp_s[ii] = new MathType[ 1];
rangeComp_s[ii][0] = range;
n_comps++;
}
else if ( range instanceof TupleType )
{
n_dims = ((TupleType)range).getDimension();
rangeComp_s[ii] = new MathType[ n_dims ];
for ( jj = 0; jj < n_dims; jj++ ) {
rangeComp_s[ii][jj] = ((TupleType)range).getComponent(jj);
}
n_comps += n_dims;
}
else
{
rangeComp_s[ii] = new MathType[1];
rangeComp_s[ii][0] = range;
n_comps++;
}
}
domainSet_0 = field_0.getDomainSet();
domainType_0 = ((FunctionType)field_0.getType()).getDomain();
n_samples_0 = domainSet_0.getLength();
if ( allFlat )
{
int n_sets;
int n_sys;
CoordinateSystem[] rangeCoordSys_s;
Field field;
boolean allReal = true;
int tupleDim = 0;
cnt = 0;
Vector coordsys_s = new Vector();
Vector m_types = new Vector();
Vector r_types = new Vector();
for ( ii = 0; ii < n_fields; ii++ )
{
field = fields[ii];
fieldRange = fieldRange_s[ii];
if ( fieldRange instanceof RealType )
{
m_types.add( fieldRange );
r_types.add( fieldRange );
rangeCoordSys_s = field.getRangeCoordinateSystem();
coordsys_s.add( rangeCoordSys_s[0] );
tupleDim++;
}
else if ( fieldRange instanceof RealTupleType )
{
n_dims = ((RealTupleType)fieldRange).getDimension();
tupleDim += n_dims;
rangeCoordSys_s = field.getRangeCoordinateSystem();
if ( rangeCoordSys_s[0] == null && flatten)
{
for ( jj = 0; jj < n_dims; jj++ )
{
m_type = ((RealTupleType)fieldRange).getComponent(jj);
m_types.add( m_type );
r_types.add( m_type );
coordsys_s.add( null );
}
}
else
{
m_types.add( fieldRange );
coordsys_s.add( rangeCoordSys_s[0] );
allReal = false;
}
}
else //- must be Flat TupleType -*
{
for ( jj = 0; jj < rangeComp_s[ii].length; jj++ )
{
rangeCoordSys_s = field.getRangeCoordinateSystem(jj);
m_type = rangeComp_s[ii][jj];
if ( m_type instanceof RealType )
{
r_types.add( m_type );
m_types.add( m_type );
coordsys_s.add( rangeCoordSys_s[0] );
tupleDim++;
}
else if ( m_type instanceof RealTupleType )
{
n_dims = ((RealTupleType)m_type).getDimension();
tupleDim += n_dims;
if ( rangeCoordSys_s[0] == null && flatten)
{
for ( kk = 0; kk < n_dims; kk++ )
{
m_types.add( ((RealTupleType)m_type).getComponent(kk) );
r_types.add( ((RealTupleType)m_type).getComponent(kk) );
coordsys_s.add( null );
}
}
else
{
m_types.add( m_type );
coordsys_s.add( rangeCoordSys_s[0] );
allReal = false;
}
}
}
}
}
if ( allReal )
{
length = r_types.size();
RealType[] r_array = new RealType[ length ];
for ( ii = 0; ii < length; ii++ ) {
r_array[ii] = (RealType) r_types.elementAt(ii);
}
new_range = new RealTupleType( r_array );
}
else
{
length = m_types.size();
MathType[] m_array = new MathType[ length ];
for ( ii = 0; ii < length; ii++ ) {
m_array[ii] = (MathType) m_types.elementAt(ii);
}
new_range = new TupleType( m_array );
}
new_type = new FunctionType( domainType_0, new_range );
length = coordsys_s.size();
CoordinateSystem[] all_rangeCoordSys_s = new CoordinateSystem[ length ];
for ( ii = 0; ii < length; ii++ )
{
all_rangeCoordSys_s[ii] = (CoordinateSystem) coordsys_s.elementAt(ii);
}
Set[] rangeSets;
Set[] new_rangeSets = new Set[ tupleDim ];
Unit[][] rangeUnits;
Unit[] new_rangeUnits = new Unit[ tupleDim ];
Unit[] sub_units;
int cnt_a = 0;
int cnt_b = 0;
int cnt_c = 0;
int cnt_u = 0;
int n_coordsys = 0;
int n_units;
boolean allFloat = true; // default set for FlatField
FlatField[] resampledFields = new FlatField[n_fields];
for ( ii = 0; ii < n_fields; ii++ )
{
f_field = (FlatField) fields[ii].local();
if ( ii > 0 ) //- don't resample field to itself even though this would
{ //- probably be no-op anyway.
f_field = (FlatField) f_field.resample( domainSet_0, sampling_mode, error_mode );
}
resampledFields[ii] = f_field;
//- collect rangeSets for each tuple dimension -*
rangeSets = f_field.getRangeSets();
n_sets = rangeSets.length;
// check for float sets
if (allFloat) {
for (int s = 0; s < n_sets; s++) {
if (!(rangeSets[s] instanceof FloatSet)) {
allFloat = false;
break;
}
}
}
System.arraycopy( rangeSets, 0, new_rangeSets, cnt_a, n_sets );
cnt_a += n_sets;
/* Don't need to do this because getSamples/Values uses default units)
//- collect rangeUnits for each tuple dimension -*
rangeUnits = f_field.getRangeUnits();
n_units = rangeUnits.length;
sub_units = new Unit[ n_units ];
for ( jj = 0; jj < n_units; jj++ ) {
sub_units[jj] = rangeUnits[jj][0];
}
System.arraycopy( sub_units, 0, new_rangeUnits, cnt_u, n_units );
cnt_u += n_units;
*/
}
// metadata collected. Now get Data
if (allFloat) {
new_valuesF = new float[ tupleDim ][];
}
else {
new_valuesD = new double[ tupleDim ][];
}
for (int f = 0; f < n_fields; f++) {
//- get range values for each field, and combine into one array -*
if (allFloat) {
valuesF = resampledFields[f].getFloats(copy);
for ( jj = 0; jj < valuesF.length; jj++ )
{
new_valuesF[cnt_b++] = valuesF[jj];
}
}
else {
valuesD = resampledFields[f].getValues(copy);
for ( jj = 0; jj < valuesD.length; jj++ )
{
new_valuesD[cnt_b++] = valuesD[jj];
}
}
}
//- data and metadata collected. Make new flatfield -*
if ( new_type.getReal() )
{
new_field = new FlatField( new_type, domainSet_0, null, null,
new_rangeSets, null );
}
else
{
new_field = new FlatField( new_type, domainSet_0, all_rangeCoordSys_s,
new_rangeSets, null );
}
//- set range values for new flatfield -*
if (allFloat) {
((FlatField)new_field).setSamples( new_valuesF, false );
}
else {
((FlatField)new_field).setSamples( new_valuesD, false );
}
}
else //- not all FlatField(s) -*
{
Vector sub_types = new Vector();
Field field;
Data[] data_s;
Data data;
Data rangeData;
boolean allReal = true;
RealTuple R_tuple;
Vector[] v_array = new Vector[ n_samples_0 ];
for ( ii = 0; ii < n_samples_0; ii++ ) {
v_array[ii] = new Vector();
}
for ( ii = 0; ii < n_fields; ii++ )
{
if ( ii == 0 ) //- resample fields to domain of first
{
field = (Field) fields[ii].local();
}
else
{
field = fields[ii].resample( domainSet_0, sampling_mode, error_mode );
}
fieldRange = fieldRange_s[ii];
if ( fieldRange instanceof RealType )
{
sub_types.add( fieldRange );
for ( kk = 0; kk < n_samples_0; kk++ ) {
v_array[kk].add( field.getSample(kk) );
}
}
else if ( fieldRange instanceof RealTupleType )
{
if ( ((RealTupleType)fieldRange).getCoordinateSystem() != null )
{
sub_types.add( fieldRange );
allReal = false;
for ( kk = 0; kk < n_samples_0; kk++ ) {
v_array[kk].add( field.getSample(kk) );
}
}
else
{
n_dims = ((RealTupleType)fieldRange).getDimension();
for ( jj = 0; jj < n_dims; jj++ )
{
sub_types.add( ((RealTupleType)fieldRange).getComponent(jj) );
}
for ( kk = 0; kk < n_samples_0; kk++ ) {
rangeData = field.getSample(kk);
for ( jj = 0; jj < n_dims; jj++ ) {
v_array[kk].add( ((RealTuple)rangeData).getComponent(jj) );
}
}
}
}
else if( (fieldRange instanceof TupleType) &&
!(fieldRange instanceof RealTupleType) )
{
if ( !(((TupleType)fieldRange).getFlat()) )
{
sub_types.add( fieldRange );
for ( kk = 0; kk < n_samples_0; kk++ ) {
v_array[kk].add( field.getSample(kk) );
}
allReal = false;
}
else
{
n_dims = ((TupleType)fieldRange).getDimension();
for ( ii = 0; ii < n_dims; ii++ )
{
m_type = ((TupleType)fieldRange).getComponent(ii);
if ( m_type instanceof RealType )
{
sub_types.add( m_type );
for ( kk = 0; kk < n_samples_0; kk++ ) {
v_array[kk].add( ((TupleIface)field.getSample(kk)).getComponent(ii));
}
}
else if ( m_type instanceof RealTupleType )
{
if ( ((RealTupleType)m_type).getCoordinateSystem() != null )
{
sub_types.add( m_type );
allReal = false;
for ( kk = 0; kk < n_samples_0; kk++ ) {
v_array[kk].add( ((TupleIface)field.getSample(kk)).getComponent(ii));
}
}
else
{
for ( jj = 0; jj < ((RealTupleType)m_type).getDimension(); jj++ )
{
sub_types.add( ((RealTupleType)m_type).getComponent(jj) );
}
for ( kk = 0; kk < n_samples_0; kk++ ) {
R_tuple = (RealTuple)((TupleIface)field.getSample(kk)).getComponent(ii);
for ( jj = 0; jj < ((RealTupleType)m_type).getDimension(); jj++ ) {
v_array[kk].add( R_tuple.getComponent(jj));
}
}
}
}
}
}
}
else if ( fieldRange instanceof FunctionType )
{
sub_types.add( fieldRange );
for ( kk = 0; kk < n_samples_0; kk++ ) {
v_array[kk].add( field.getSample(kk) );
}
allReal = false;
}
} //- all fields loop -*
int size = sub_types.size();
if ( allReal )
{
RealType[] r_types = new RealType[ size ];
for ( ii = 0; ii < size; ii++ ) {
r_types[ii] = (RealType) sub_types.elementAt(ii);
}
new_range = new RealTupleType( r_types );
}
else
{
MathType[] m_types = new MathType[ size ];
for ( ii = 0; ii < size; ii++ ) {
m_types[ii] = (MathType) sub_types.elementAt(ii);
}
new_range = new TupleType( m_types );
}
new_type = new FunctionType( domainType_0, new_range );
new_field = new FieldImpl( new_type, domainSet_0 );
for ( ii = 0; ii < n_samples_0; ii++ )
{
size = v_array[ii].size();
data_s = new Data[ size ];
for ( jj = 0; jj < size; jj++ )
{
data_s[jj] = (Data) v_array[ii].elementAt( jj );
}
data = new Tuple( data_s );
new_field.setSample( ii, data, copy );
}
}
visad.util.Trace.call2("combine, copy = " + copy);
return new_field;
}
/** extract Field from this.component using the MathType
* of one of the range componenets
*/
public Field extract(MathType type) throws VisADException, RemoteException {
int index = -1;
MathType rangeType = ((FunctionType)Type).getRange();
if (!(rangeType instanceof TupleType)) {
throw new VisADException("FieldImpl.extract: range must be a TupleType");
}
int n_comps = ((TupleType)rangeType).getDimension();
for (int i=0; i<n_comps; i++) {
MathType test_comp = ((TupleType)rangeType).getComponent(i);
if (test_comp.equals(type) ) {
index = i;
break;
}
}
if (index != -1) {
return extract(index);
} else {
return null; //?
}
}
/** extract Field from this.component using the name
* of one of the range componenets
*/
public Field extract(String name) throws VisADException, RemoteException {
int index = -1;
MathType rangeType = ((FunctionType)Type).getRange();
if (!(rangeType instanceof TupleType)) {
throw new VisADException("FieldImpl.extract: range must be a TupleType");
}
int n_comps = ((TupleType)rangeType).getDimension();
for (int i=0; i<n_comps; i++) {
String test_comp = ((TupleType)rangeType).getComponent(i).toString();
if (test_comp.equals(name) || test_comp.equals("("+name+")")) {
index = i;
break;
}
}
if (index != -1) {
return extract(index);
} else {
return null; //?
}
}
/** extract field from this[].component */
public Field extract(int component)
throws VisADException, RemoteException
{
Set domainSet = getDomainSet();
int n_samples = domainSet.getLength();
MathType rangeType = ((FunctionType)Type).getRange();
MathType domainType = ((FunctionType)Type).getDomain();
Data rangeData;
Data new_rangeData;
Unit[] new_unit;
Unit unit;
double[][] values, t_values;
double value;
CoordinateSystem coord_sys, coord_in, coord_out;
MathType m_type;
RealTupleType rt_type;
RealType r_type;
Real real;
RealTuple r_tuple;
FieldImpl new_field;
int ii, jj, kk, t_dim, dim, n_coordsys;
if (!( rangeType instanceof TupleType) )
{
throw new VisADException("extract: range type must be TupleType");
}
int n_comps = ((TupleType)rangeType).getDimension();
if (component == 0 && n_comps == 1) return this;
if ( (component + 1) > n_comps )
{
throw new VisADException("extract: component selection too large");
}
MathType new_range = ((TupleType)rangeType).getComponent( component );
FunctionType new_type = new FunctionType( domainType, new_range);
if ( new_range instanceof RealType )
{
new_unit = new Unit[1];
new_unit[0] = ((RealType)new_range).getDefaultUnit();
new_field = new FlatField( new_type, domainSet, null, null, null, new_unit );
values = new double[1][n_samples];
for ( ii = 0; ii < n_samples; ii++ )
{
real = (Real)
((TupleIface) getSample(ii)).getComponent( component );
value = real.getValue();
if (new_unit[0] != null) {
unit = real.getUnit();
values[0][ii] = new_unit[0].toThis( value, unit );
}
else {
values[0][ii] = value;
}
}
((FlatField)new_field).setSamples( values, false );
}
else if ( new_range instanceof RealTupleType )
{
coord_out = ((RealTupleType)new_range).getCoordinateSystem();
dim = ((RealTupleType)new_range).getDimension();
Unit[] unit_out = new Unit[dim];
Unit[] unit_in = new Unit[dim];
unit_out = ((RealTupleType)new_range).getDefaultUnits();
new_field = new FlatField( new_type, domainSet, coord_out, null, unit_out );
values = new double[ dim ][ n_samples ];
t_values = new double[ dim ][ 1];
for ( ii = 0; ii < n_samples; ii++ )
{
r_tuple = (RealTuple)
((TupleIface) getSample(ii)).getComponent( component );
coord_in = r_tuple.getCoordinateSystem();
unit_in = r_tuple.getTupleUnits();
for ( jj = 0; jj < dim; jj++ )
{
t_values[jj][0] = ((Real)r_tuple.getComponent(jj)).getValue();
}
t_values = CoordinateSystem.transformCoordinates(
(RealTupleType)new_range, coord_out, unit_out, null,
(RealTupleType)new_range, coord_in, unit_in, null, t_values );
for ( jj = 0; jj < dim; jj++ )
{
values[jj][ii] = t_values[jj][0];
}
}
((FlatField)new_field).setSamples( values, false );
}
else if (( new_range instanceof TupleType) && ( ((TupleType)new_range).getFlat()) )
{
new_field = new FlatField( new_type, domainSet );
dim = ((TupleType)new_range).getDimension();
t_dim = 0;
n_coordsys = 0;
for ( ii = 0; ii < dim; ii++ )
{
m_type = ((TupleType)new_range).getComponent(ii);
if ( m_type instanceof RealType )
{
t_dim++;
}
else if ( m_type instanceof RealTupleType )
{
rt_type = (RealTupleType)m_type;
t_dim += (rt_type).getDimension();
if ( rt_type.getCoordinateSystem() != null )
{
n_coordsys++;
}
}
}
values = new double[ t_dim ][ n_samples ];
t_dim = 0;
for ( ii = 0; ii < n_samples; ii++ )
{
rangeData = getSample(ii);
m_type = rangeData.getType();
for ( jj = 0; jj < dim; jj++ )
{
if ( m_type instanceof RealType )
{
values[t_dim][ii] =
((Real)((TupleIface)rangeData).getComponent(jj)).getValue();
t_dim++;
}
else
{
r_tuple = (RealTuple) ((TupleIface)rangeData).getComponent(jj);
for ( kk = 0; kk < ((RealTupleType)m_type).getDimension(); kk++ )
{
values[t_dim][ii] = ((Real)r_tuple.getComponent(kk)).getValue();
t_dim++;
}
}
}
}
((FlatField)new_field).setSamples( values, false );
}
else
{
new_field = new FieldImpl( new_type, domainSet );
for ( ii = 0; ii < n_samples; ii++ )
{
rangeData = getSample(ii);
new_rangeData = ((TupleIface)rangeData).getComponent( component );
new_field.setSample( ii, new_rangeData, false );
}
}
return new_field;
}
/**
* Factors this instance into a (nested) field-of-fields. The type of the
* domain of the outer field will be the type specified. The type of the
* domains of the inner fields will be the remainder of the original domain
* after the outer domain is factored out. Range data is not copied for
* FieldImpls, but will be for FlatFields.
* @see #domainFactor(RealType, boolean) for copy information
*
* @param factor The type of the domain for the outer field.
* @return The field-of-fields realization of this
* instance.
* @throws DomainException The domain of this instance cannot be factored
* as requested.
* @throws VisADException VisAD failure.
* @throws RemoteException Java RMI failure.
*/
public Field domainFactor( RealType factor )
throws DomainException, VisADException, RemoteException
{
return domainFactor(factor, false);
}
/**
* Factors this instance into a (nested) field-of-fields. The type of the
* domain of the outer field will be the type specified. The type of the
* domains of the inner fields will be the remainder of the original domain
* after the outer domain is factored out. Range data is copied if
*
* @param factor The type of the domain for the outer field.
* @param copy true to make copies of the data objects
* @return The field-of-fields realization of this
* instance.
* @throws DomainException The domain of this instance cannot be factored
* as requested.
* @throws VisADException VisAD failure.
* @throws RemoteException Java RMI failure.
*/
public Field domainFactor( RealType factor, boolean copy )
throws DomainException, VisADException, RemoteException
{
int factorIndex;
Set factor_domain = null;
int length;
int[] lengths = null;
int[] new_lengths = null;
int[] dim_lengths = null;
int[] dim_product = null;
int[] sub_domain = null;
Set new_domain = null;
RealTupleType new_domain_type = null;
FieldImpl factor_field = null;
FunctionType new_type = null;
Data range;
Data[] new_range_data = null;
int ii, jj, kk, cnt;
int mm, nn, index;
RealTupleType domainType = ((FunctionType)Type).getDomain();
MathType rangeType = ((FunctionType)Type).getRange();
int domainDim = domainType.getDimension();
RealType[] r_types = new RealType[domainDim - 1];
if ((factorIndex = domainType.getIndex((MathType)factor)) < 0 ) {
throw new DomainException(
"domainFactor: factor not element of domain");
}
cnt = 0;
for ( ii = 0; ii < domainDim; ii++ ) {
if ( ii != factorIndex ) {
r_types[cnt++] = (RealType) domainType.getComponent(ii);
}
}
new_domain_type = new RealTupleType(r_types);
Set domainSet = getDomainSet();
if ( domainSet instanceof LinearSet )
{
factor_domain = ((LinearSet)domainSet).getLinear1DComponent( factorIndex );
dim_lengths = ((GriddedSet)domainSet).getLengths();
Linear1DSet[] L1D_sets = new Linear1DSet[domainDim - 1];
new_lengths = new int[ domainDim - 1 ];
sub_domain = new int[domainDim - 1];
cnt = 0;
for ( ii = 0; ii < domainDim; ii++ ) {
if ( ii != factorIndex ) {
L1D_sets[cnt] = ((LinearSet)domainSet).getLinear1DComponent(ii);
new_lengths[cnt] = L1D_sets[cnt].LengthX;
sub_domain[cnt] = ii;
cnt++;
}
}
new_domain = new LinearNDSet( new_domain_type, L1D_sets );
new_type = new FunctionType( new_domain_type, rangeType );
}
else if ( domainSet instanceof GriddedSet )
{
//- check for R^N aligned set? If aligned then should
//- be created as a ProductSet for efficiency
throw new DomainException(
"domainFactor: DomainSet is GriddedSet, if aligned use ProductSet" );
}
else if ( domainSet instanceof ProductSet )
{
ProductSet prod_set = (ProductSet)((ProductSet)domainSet).product();
SampledSet[] sets = prod_set.Sets;
int n_sets = sets.length;
SampledSet[] sub_sets = new SampledSet[n_sets - 1];
SampledSet factor_set = null;
SampledSet fin_factor_set = null;
int sub_factor_index = -1;
int fac_set_idx = -1;
int fac_set_len = -1;
int[] sub_set_idx = new int[n_sets - 1];
int[] sub_set_lengths = new int[n_sets - 1];
cnt = 0;
for ( kk = 0; kk < n_sets; kk++ ) {
SetType s_type = (SetType) sets[kk].getType();
if ((sub_factor_index = s_type.getDomain().getIndex((MathType)factor)) >= 0 ) {
factor_set = sets[kk];
fac_set_idx = kk;
fac_set_len = factor_set.getLength();
}
else {
sub_sets[cnt] = sets[kk];
sub_set_idx[cnt] = kk;
sub_set_lengths[cnt] = sets[kk].getLength();
cnt++;
}
}
int factor_set_dim = factor_set.getDimension();
int n_sub_sets = sub_sets.length;
if ( factor_set_dim == 1 )
{
fin_factor_set = factor_set;
new_lengths = new int[n_sub_sets];
sub_domain = new int[n_sub_sets];
dim_lengths = new int[n_sets];
if ( n_sub_sets > 1 ) {
new_domain = (Set) new ProductSet(sub_sets);
}
else {
new_domain = (Set) sub_sets[0];
}
factor_domain = factor_set;
System.arraycopy(sub_set_lengths, 0, new_lengths, 0, n_sub_sets);
System.arraycopy(sub_set_idx, 0, sub_domain, 0, n_sub_sets);
for ( ii = 0; ii < n_sub_sets; ii++ ) {
dim_lengths[sub_set_idx[ii]] = sub_set_lengths[ii];
}
dim_lengths[fac_set_idx] = fac_set_len;
new_type =
new FunctionType(
((SetType)new_domain.getType()).getDomain(), rangeType );
}
else if (!(factor_set instanceof LinearNDSet ))
{
throw new DomainException(
"cannot factor into "+factor_set.getClass());
}
else
{
MathType n_type = null;
new_lengths = new int[n_sub_sets + 1];
sub_domain = new int[n_sub_sets + 1];
dim_lengths = new int[n_sets + 1];
Linear1DSet[] L1D_sets = new Linear1DSet[factor_set_dim - 1];
cnt = 0;
for ( ii = 0; ii < factor_set_dim; ii++ ) {
if ( ii != sub_factor_index ) {
L1D_sets[cnt] = ((LinearSet)domainSet).getLinear1DComponent(ii);
cnt++;
}
else {
fin_factor_set = ((LinearSet)domainSet).getLinear1DComponent(ii);
}
}
Set new_set = new LinearNDSet(n_type, L1D_sets);
cnt = 0;
System.arraycopy(sub_set_lengths, 0, new_lengths, 0, fac_set_idx);
System.arraycopy(sub_set_idx, 0, sub_domain, 0, fac_set_idx);
cnt += fac_set_idx;
new_lengths[fac_set_idx] = new_set.getLength();
cnt += 1;
System.arraycopy(sub_set_lengths, fac_set_idx, new_lengths, cnt,
(n_sub_sets - fac_set_idx));
System.arraycopy(sub_set_idx, fac_set_idx, sub_domain, cnt,
(n_sub_sets - fac_set_idx));
new_type =
new FunctionType(
((SetType)new_set.getType()).getDomain(), rangeType );
new_domain = new_set;
}
}
else if ( domainSet instanceof UnionSet )
{
throw new UnimplementedException(
"domainFactor: DomainSet is UnionSet" );
}
else if ( domainSet instanceof IrregularSet )
{
throw new DomainException(
"domainFactor: DomainSet is IrregularSet, can't factor" );
}
length = factor_domain.getLength();
new_range_data = new Data[ length ];
dim_product = new int[domainDim];
for ( kk = 0; kk < domainDim; kk++ ) {
dim_product[kk] = 1;
for ( mm = 0; mm < kk; mm++ ) {
dim_product[kk] *= dim_lengths[mm];
}
}
int s_dims = new_lengths.length;
int[] indexes = new int[ s_dims ];
int product = 1;
for ( ii = 0; ii < s_dims; ii++ ) {
product *= new_lengths[ii];
}
int[] work = new int[product];
for ( int k = 0; k < product; k++ )
{
int k2 = k;
for ( int j = (s_dims-1); j >= 0; j-- ) {
int temp = 1;
for ( int m = 0; m < j; m++ ) {
temp *= new_lengths[m];
}
indexes[j] = k2/temp;
k2 -= temp*indexes[j];
}
for ( int t = 0; t < indexes.length; t++ ) {
work[k] += dim_product[sub_domain[t]]*indexes[t];
}
}
if ( isFlatField() )
{
double[][] old_range_values = getValues(false);
int tup_dim = old_range_values.length;
for ( ii = 0; ii < length; ii++ )
{
double[][] new_range_values = new double[tup_dim][work.length];
FlatField new_field = new FlatField( new_type, new_domain );
for ( jj = 0; jj < work.length; jj++ ) {
index = 0;
index = ii*dim_product[factorIndex];
index += work[jj];
for ( kk = 0; kk < tup_dim; kk++ ) {
new_range_values[kk][jj] = old_range_values[kk][ index ];
}
}
((FlatField)new_field).setSamples( new_range_values, false );
new_range_data[ii] = new_field;
}
}
else
{
for ( ii = 0; ii < length; ii++ )
{
FieldImpl new_field = new FieldImpl( new_type, new_domain );
for ( jj = 0; jj < work.length; jj++ ) {
index = 0;
index = ii*dim_product[factorIndex];
index += work[jj];
new_range_data[jj] = this.getSample(index);
}
new_field.setSamples( new_range_data, false, false );
new_range_data[ii] = new_field;
}
}
factor_field = new FieldImpl( new FunctionType( factor, new_type),
factor_domain );
factor_field.setSamples( new_range_data, copy, false );
return factor_field;
}
/**
* Combine domains of two outermost nested Fields into a single
* domain and Field. If the domains each have <code>
* CoordinateSystem</code>-s the new domain will have
* a <code>CartesianProductCoordinateSystem</code> of
* Set-s CoordinateSystems
*
* @throws VisADException unable to collapse domains
* @throws RemoteException unable to collapse domains of remote data
*/
public Field domainMultiply()
throws VisADException, RemoteException
{
return domainMultiply(1, null);
}
/**
* Combine domains of two outermost nested Fields into a single
* domain and Field. The supplied <code>resultCS</code> would be used
* for the new domain
* @param resultCS CoordinateSystem to use for the new domain set
* @throws VisADException unable to collapse domains
* @throws RemoteException unable to collapse domains of remote data
*/
public Field domainMultiply(CoordinateSystem resultCS)
throws VisADException, RemoteException
{
return domainMultiply(1, resultCS);
}
/**
* Combine domains of <code>collapse_depth</code> if possible.
* @param collapse_depth depth to collapse to
* @throws VisADException unable to collapse domains
* @throws RemoteException unable to collapse domains of remote data
*/
public Field domainMultiply(int collapse_depth)
throws VisADException, RemoteException
{
return domainMultiply(collapse_depth, null);
}
/**
* Combine domains of <code>collapse_depth</code> if possible.
* Use <code>resultCS</code> as the CoordinateSystem for the new domain.
* @param collapse_depth depth to collapse to
* @param resultCS CoordinateSystem to use for the new domain set
* @throws VisADException unable to collapse domains
* @throws RemoteException unable to collapse domains of remote data
*/
public Field domainMultiply(int collapse_depth, CoordinateSystem resultCS)
throws VisADException, RemoteException
{
class Helper
{
int cnt = 0;
int n_samples;
int depth;
int depth_max;
boolean flat;
MathType range_type;
MathType new_range_type;
SampledSet[] last_set;
SampledSet[] fac_sets;
Data[] collapse_array;
public Helper(Data data, int col_depth)
throws VisADException, RemoteException
{
MathType m_type = data.getType();
depth = 0;
flat = false;
depth_max = checkType( m_type );
if ( depth_max == 0 )
{
throw new FieldException("MathType "+m_type.prettyString());
}
else if ( depth_max >= col_depth )
{
depth_max = col_depth;
}
flat = false;
for (int kk = 0; kk < depth_max; kk++) {
if (m_type instanceof FunctionType) {
m_type = ((FunctionType)m_type).getRange();
}
}
if (m_type instanceof FunctionType) {
flat = ((FunctionType)m_type).getFlat();
new_range_type = ((FunctionType)m_type).getRange();
}
last_set = new SampledSet[depth_max + 1];
depth = 0;
if ( !(setsEqual((Field)data)) )
{
throw new FieldException("sets not equal");
}
int length = 1;
if (flat) {
for ( int kk = 0; kk < depth_max; kk++ ) {
length *= last_set[kk].getLength();
}
}
else {
for ( int kk = 0; kk < depth_max+1; kk++ ) {
length *= last_set[kk].getLength();
}
}
collapse_array = new Data[length];
depth = 0;
collapse( data );
}
public SampledSet[] getSets() {
int length = last_set.length;
fac_sets = new SampledSet[length];
for ( int ii = 0; ii < length; ii++ ) {
fac_sets[(length-1) - ii] = last_set[ii];
}
return fac_sets;
}
public Data[] getRangeArray() {
return collapse_array;
}
public MathType getRangeType() {
return new_range_type;
}
public int checkType(MathType m_type) //-- analyze Data hierarchy
throws VisADException, RemoteException
{
if ( m_type instanceof FunctionType )
{
if (((FunctionType)m_type).getFlat())
{
flat = true;
new_range_type = ((FunctionType)m_type).getRange();
return depth;
}
else
{
range_type = ((FunctionType)m_type).getRange();
depth++;
return checkType(range_type);
}
}
else
{
new_range_type = m_type;
return depth;
}
}
public void collapse( Data data )
throws VisADException, RemoteException
{
if ( depth == depth_max )
{
if (flat)
{
collapse_array[cnt++] = ((FieldImpl)data);
}
else
{
for ( int ii = 0; ii < ((FieldImpl)data).getLength(); ii++) {
collapse_array[cnt++] = ((FieldImpl)data).getSample(ii);
}
}
}
else
{
int n_samples = (((Field)data).getDomainSet()).getLength();
for ( int ii = 0; ii < n_samples; ii++ ) {
depth++;
collapse(((FieldImpl)data).getSample(ii));
depth--;
}
}
}
public boolean setsEqual( Field field )
throws VisADException, RemoteException
{
Set domainSet = field.getDomainSet();
int n_samples = domainSet.getLength();
if ( depth == 0 ) {
last_set[depth] = (SampledSet)domainSet;
}
depth++;
if (last_set[depth] == null ) {
last_set[depth] = (SampledSet)((Field)(field.getSample(0))).getDomainSet();
}
for ( int ii = 0; ii < n_samples; ii++ )
{
Field range_data = (Field) field.getSample(ii);
Set range_set = range_data.getDomainSet();
if ( !(last_set[depth].equals(range_set)) )
{
return false;
}
if ( !(depth == (depth_max)) )
{
if ( !(setsEqual(range_data)) )
{
return false;
}
depth--;
}
}
return true;
}
} //- end helper class
int cnt;
SampledSet new_set = null;
int n_irregular = 0;
int n_linear = 0;
int new_domainDim = 0;
int new_manifoldDim = 0;
Helper helper = new Helper(this, collapse_depth);
SampledSet[] fac_sets = helper.getSets();
int n_sets = fac_sets.length;
Data[] new_range = helper.getRangeArray();
MathType new_range_type = helper.getRangeType();
SetType[] set_types = new SetType[n_sets];
int new_length = 1;
for ( int kk = 0; kk < n_sets; kk++ )
{
new_length *= fac_sets[kk].getLength();
new_domainDim += fac_sets[kk].getDimension();
new_manifoldDim += fac_sets[kk].getManifoldDimension();
set_types[kk] = (SetType) fac_sets[kk].getType();
if ( fac_sets[kk] instanceof IrregularSet ) {
n_irregular++;
}
else if ( fac_sets[kk] instanceof LinearSet ) {
n_linear++;
}
}
RealType[] r_types = new RealType[new_domainDim];
cnt = 0;
boolean any_are_null = false;
CoordinateSystem[] coord_sys = new CoordinateSystem[n_sets];
for ( int kk = 0; kk < n_sets; kk++ ) {
RealTupleType domain = set_types[kk].getDomain();
//- TDR: May, 2003
CoordinateSystem cs = domain.getCoordinateSystem();
if (cs == null) {
any_are_null = true;
}
coord_sys[kk] = cs;
for ( int j = 0; j < domain.getDimension(); j++ ) {
r_types[cnt++] = (RealType) domain.getComponent(j);
}
}
//- TDR: May, 2003
CoordinateSystem new_cs = resultCS;
if (!any_are_null && new_cs == null) {
new_cs = coord_sys[0];
for ( int kk = 0; kk < (coord_sys.length - 1); kk++ ) {
new_cs = new CartesianProductCoordinateSystem(new_cs, coord_sys[kk+1]);
}
}
RealTupleType new_domain_type = new RealTupleType( r_types, new_cs, null );
FunctionType new_function_type = new FunctionType( new_domain_type,
new_range_type );
if ( n_irregular > 0 ) //- if any irregular sets --> ProductSet
{
new_set = new ProductSet(fac_sets);
}
else if ( n_linear == n_sets ) //- all Linear sets
{
Linear1DSet[] L1D_sets = new Linear1DSet[new_domainDim];
cnt = 0;
for ( int kk = 0; kk < n_sets; kk++ ) {
for ( int jj = 0; jj < fac_sets[kk].getDimension(); jj++ ) {
L1D_sets[cnt++] = ((LinearSet)fac_sets[kk]).getLinear1DComponent(jj);
}
}
new_set = new LinearNDSet(new_domain_type, L1D_sets);
}
else //- some Linear, some Gridded --> GriddedNDSet
{
Set set;
int sub_manifoldDim;
int domainDim;
int[] lengths;
float[][] samples;
float[][] new_samples = new float[new_domainDim][new_length];
float[][] sub_samples = new float[new_domainDim][];
Unit[] newUnits = new Unit[new_domainDim];
ErrorEstimate[] newErrors = new ErrorEstimate[new_domainDim];
int[][] manifoldLengths = new int[new_domainDim][];
int[][] manifoldIndexes = new int[new_domainDim][];
int[] new_lengths = new int[new_manifoldDim];
cnt = 0;
int cnt_m = 0;
int manifoldDimension = 0;
for ( int kk = 0; kk < n_sets; kk++ )
{
set = fac_sets[kk];
samples = ((SampledSet)set).getSamples();
domainDim = set.getDimension();
sub_manifoldDim = set.getManifoldDimension();
lengths = ((GriddedSet)set).getLengths();
Unit[] units = set.getSetUnits();
ErrorEstimate[] errors = set.getSetErrors();
for ( int ii = 0; ii < domainDim; ii++ ) {
sub_samples[cnt] = samples[ii];
manifoldLengths[cnt] = lengths;
manifoldIndexes[cnt] = new int[sub_manifoldDim];
for ( int jj = 0; jj < sub_manifoldDim; jj++ ) {
manifoldIndexes[cnt][jj] = jj + manifoldDimension;
}
newUnits[cnt] = units[ii];
newErrors[cnt] = errors[ii];
cnt++;
}
for ( int ii = 0; ii < sub_manifoldDim; ii++ ) {
new_lengths[cnt_m++] = lengths[ii];
}
manifoldDimension += sub_manifoldDim;
}
int[] indexes = new int[new_manifoldDim];
for ( int k = 0; k < new_length; k++ )
{
int k2 = k;
for ( int j = (new_manifoldDim - 1); j >= 0; j-- ) {
int temp = 1;
for ( int m = 0; m < j; m++ ) {
temp *= new_lengths[m];
}
indexes[j] = k2/temp;
k2 -= temp*indexes[j];
}
for ( int ii = 0; ii < new_domainDim; ii++ )
{
int sub_index = 0;
for ( int mm = (manifoldIndexes[ii].length - 1); mm >= 0; mm-- ) {
int product = 1;
for ( int nn = 0; nn < mm; nn++ ) {
product *= manifoldLengths[ii][nn];
}
product *= indexes[manifoldIndexes[ii][mm]];
sub_index += product;
}
new_samples[ii][k] = sub_samples[ii][sub_index];
}
}
// DRM 02-Feb-2003
//new_set = new GriddedSet(new_domain_type, new_samples, new_lengths );
//new_set = GriddedSet.create(new_domain_type, new_samples, new_lengths );
new_set = GriddedSet.create(new_domain_type, new_samples, new_lengths,
null, // CS null, because already defined in new_domain_type
newUnits, newErrors);
}
Field new_field;
if ( helper.flat )
{
new_field = new FlatField( new_function_type, new_set );
int tup_dim =
(new_function_type.getFlatRange()).getDimension();
double[][] new_values =
new double[tup_dim][new_length];
cnt = 0;
double[][] sub_range;
for ( int ii = 0; ii < new_range.length; ii++ ) {
sub_range = ((FieldImpl) new_range[ii]).getValues(false);
int len = sub_range[0].length;
for ( int jj = 0; jj < tup_dim; jj++ ) {
System.arraycopy(sub_range[jj], 0, new_values[jj], cnt, len);
}
cnt += len;
}
// still a problem if a factor Set is doubles (e.g., Time)
// WLH 15 Jan 2000
((FlatField) new_field).setSamples(new_values, false);
}
else
{
new_field = new FieldImpl( new_function_type, new_set );
for ( int ii = 0; ii < new_length; ii++ ){
new_field.setSample(ii, new_range[ii]);
}
}
return new_field;
}
public Data derivative( RealTuple location, RealType[] d_partial_s,
MathType[] derivType_s, int error_mode )
throws VisADException, RemoteException
{
int ii, jj, kk, dd, rr, tt, pp, ss;
Set domainSet = this.getDomainSet();
int domainDim = domainSet.getDimension();
int manifoldDimension = domainSet.getManifoldDimension();
int n_samples = domainSet.getLength();
CoordinateSystem d_coordsys = this.getDomainCoordinateSystem();
RealTupleType d_reference = (d_coordsys == null) ? null : d_coordsys.getReference();
MathType m_type = null;
MathType[] m_types = null;
RealType r_type = null;
RealType[] r_types = null;
TupleType t_type = null;
boolean thisDomainFlag = true;
if ( manifoldDimension != domainDim )
{
throw new SetException("derivative: manifoldDimension must equal "+
"domain dimension" );
}
error_mode = Data.NO_ERRORS;
int sampling_mode = Data.WEIGHTED_AVERAGE;
if ( location != null )
{
thisDomainFlag = false;
}
RealTupleType domainType = ((FunctionType)Type).getDomain();
RealType[] r_comps = domainType.getRealComponents();
RealType[] r_compsRef = (d_reference == null) ? null : d_reference.getRealComponents();
MathType RangeType = ((FunctionType)Type).getRange();
int n_partials; // number of partial derivatives to compute -*
//- get all components for this function's domain -*
if ( d_partial_s == null )
{
n_partials = domainDim;
d_partial_s = r_comps;
}
else
{
n_partials = d_partial_s.length;
if ( n_partials > domainDim ) {
throw new VisADException("derivative: too many d_partial components");
}
}
int[] u_index = new int[n_partials];
double[][] u_vectors = new double[n_partials][domainDim];
//- verify that input RealType-s match the Function's domain -*
//- create unit vectors for the d_partial RealTypes -*
int found = 0;
int foundRef = 0;
for ( ii = 0; ii < n_partials; ii++ )
{
for ( jj = 0; jj < domainDim; jj++ )
{
u_vectors[ii][jj] = 0d;
if ( r_comps[jj].equals(d_partial_s[ii]) )
{
u_index[ii] = jj;
u_vectors[ii][jj] = 1d;
found++;
}
else if ( d_reference != null )
{
if ( r_compsRef[jj].equals(d_partial_s[ii]) )
{
u_index[ii] = jj;
u_vectors[jj][ii] = 1d;
foundRef++;
}
}
}
}
boolean transform; //- flag indicating coordinate transform is required --*
if ( found == 0 )
{
if ( foundRef == 0 )
{
throw new VisADException("derivative: d_partial_s not in domain or reference");
}
else if ( 0 < foundRef && foundRef < n_partials )
{
throw new VisADException("derivative: d_partial_s must ALL be in function's "+
"domain or ALL in domain's reference");
}
else
{
transform = true;
}
}
else if ( 0 < found && found < n_partials )
{
throw new VisADException("derivative: d_partial_s must ALL be in function's "+
"domain or ALL in domain's reference");
}
else
{
transform = false;
}
String[][] derivNames = null;
Unit[] D_units;
MathType[] new_range = new MathType[ n_partials ];
MathType[] new_types = new MathType[ n_partials ];
if ( !transform ) {
D_units = domainSet.getSetUnits();
}
else {
D_units = d_reference.getDefaultUnits();
}
if ( derivType_s == null )
{
for ( ii = 0; ii < n_partials; ii++ )
{
MathType M_type = Type.cloneDerivative( d_partial_s[ii] );
if ( thisDomainFlag ) {
new_types[ii] = M_type;
}
else {
new_types[ii] = ((FunctionType)M_type).getRange();
}
}
derivType_s = new_types;
}
else //- check supplied derivType-s for compatibility -*
{
if ( derivType_s.length != n_partials ) {
throw new VisADException("derivative: must be a single MathType "+
"for each domain RealType");
}
for ( ii = 0; ii < n_partials; ii++ )
{
if ( thisDomainFlag ) {
if ( !Type.equalsExceptName(derivType_s[ii]) ) {
throw new TypeException("derivative: incompatible with function range");
}
}
else {
if ( !((((FunctionType)Type).getRange()).equalsExceptName(derivType_s[ii])) ) {
throw new TypeException("derivative: incompatible with function range");
}
}
}
}
//- compute derivative-s, return FlatField or Tuple of FlatFields, or Data --*
int[][] neighbors = null;
int n_points;
int n_index;
int m_index;
int index;
float distance;
float step;
float f_sum;
double d_sum;
Data[] p_derivatives = new Data[ n_partials ];
ErrorEstimate[] domainErrors = domainSet.getSetErrors();
Real deltaDomain;
FieldImpl[] new_fields = new FieldImpl[ n_partials ];
Data data_0;
Data data_1;
Data rangeDiff;
Data newRange;
Data[] rangeValues = null;
for ( pp = 0; pp < n_partials; pp++ ) {
new_fields[pp] = new FieldImpl( (FunctionType)derivType_s[pp], domainSet );
}
if ( isMissing() ) //- Bypass computations and return missing field -*
{
//- Handle LinearSet case separately for efficiency -*
if(( domainSet instanceof LinearSet )&&( thisDomainFlag ))
{
//- each partial derivative -*
for ( kk = 0; kk < n_partials; kk++ )
{
RangeType = ((FunctionType)derivType_s[kk]).getRange();
//- get manifoldDimension index for this real axis ( LinearSet only ) -*
m_index = u_index[kk];
//- get neigbors and separation along this axis -*
neighbors = domainSet.getNeighbors( m_index );
step = (float) (((LinearSet)domainSet).getLinear1DComponent(kk)).getStep();
//- compute derivative for each sample and each range component -*
for ( ii = 0; ii < n_samples; ii++ )
{
if ( neighbors[ii][0] == -1) {
distance = step;
n_index = neighbors[ii][1];
index = ii;
}
else if ( neighbors[ii][1] == -1 ) {
distance = step;
n_index = ii;
index = neighbors[ii][0];
}
else {
distance = 2.f*step;
n_index = neighbors[ii][1];
index = neighbors[ii][0];
}
data_1 = getSample(n_index);
data_0 = getSample(index);
deltaDomain = new Real( d_partial_s[kk], distance, D_units[m_index] );
rangeDiff = data_1.binary( data_0, Data.SUBTRACT, sampling_mode, error_mode);
newRange = rangeDiff.binary( deltaDomain, Data.DIVIDE, RangeType,
sampling_mode, error_mode );
new_fields[kk].setSample( ii, newRange );
}
}
}
else //- GriddedSet, IrregularSet --*
{
float dotproduct;
float inv_dotproduct;
float[][] weights = null;
float sum_weights;
float[][] Samples;
//- compute derivative at this Set's sample locations --*
if ( thisDomainFlag )
{
neighbors = new int[n_samples][];
weights = new float[n_samples][];
domainSet.getNeighbors( neighbors, weights );
if ( transform )
{
Samples = domainSet.getSamples(true);
Samples =
CoordinateSystem.transformCoordinates( d_reference, null, null, null,
domainType, d_coordsys, null, null, Samples );
}
else
{
Samples = domainSet.getSamples(false);
}
}
//- compute derivative at selected ( probably interpolated locations ) --*
else
{
Data[] new_rangeValues;
int[][] new_neighbors;
n_samples = 1;
Field field;
float[][] new_Samples;
float[][] evalSamples;
float[][] org_Samples = domainSet.getSamples(false);
field = resample( new SingletonSet(location, null, null, null ),
Data.WEIGHTED_AVERAGE, error_mode );
evalSamples = (field.getDomainSet()).getSamples(false);
neighbors = new int[n_samples][];
weights = new float[n_samples][];
((SimpleSet)domainSet).valueToInterp( evalSamples, neighbors, weights );
n_points = neighbors[0].length;
new_neighbors = new int[n_samples][ n_points ];
new_rangeValues = new Data[ n_points + 1 ];
new_Samples = new float[ domainDim ][ n_points + 1 ];
for ( ii = 0; ii < domainDim; ii++ )
{
new_Samples[ii][0] = evalSamples[ii][0];
}
new_rangeValues[0] = field.getSample(0);
for ( kk = 0; kk < n_points; kk++ )
{
new_neighbors[0][kk] = kk + 1;
new_rangeValues[kk+1] = getSample( neighbors[0][kk] );
for ( ii = 0; ii < domainDim; ii++ )
{
new_Samples[ii][kk+1] = org_Samples[ii][ neighbors[0][kk] ];
}
}
neighbors = new_neighbors;
rangeValues = new_rangeValues;
Samples = new_Samples;
if ( transform )
{
Samples =
CoordinateSystem.transformCoordinates( d_reference, null, null, null,
domainType, d_coordsys, null, null, Samples );
}
}
//- compute derivatives for each sample --*
for ( ii = 0; ii < n_samples; ii++ )
{
n_points = neighbors[ii].length;
Data[] rangeDiff_s = new Data[ n_points ];
Data p_derivative = null;
double[][] uvecPoint = new double[ n_points ][ domainDim ];
data_0 = (thisDomainFlag) ? getSample( ii ) : rangeValues[ii];
float factor;
//- neighbors loop -*
for ( kk = 0; kk < n_points; kk++ )
{
for ( dd = 0; dd < domainDim; dd++ ) {
uvecPoint[kk][dd] = Samples[dd][ neighbors[ii][kk] ] - Samples[dd][ii];
}
data_1 = (thisDomainFlag) ? getSample( neighbors[ii][kk] ) :
rangeValues[ neighbors[ii][kk] ];
rangeDiff_s[kk] = data_1.binary( data_0, Data.SUBTRACT, sampling_mode,
error_mode );
}
//- Interpolate for each partial derivative -*
boolean first = true;
for ( pp = 0; pp < n_partials; pp++ )
{
m_index = u_index[pp];
RangeType = ((FunctionType)derivType_s[pp]).getRange();
sum_weights = 0f;
for ( kk = 0; kk < n_points; kk++ )
{
dotproduct = 0;
for ( dd = 0; dd < domainDim; dd++ )
{
dotproduct += uvecPoint[kk][dd]*u_vectors[pp][dd];
}
inv_dotproduct = 1f/dotproduct;
if ( ! Float.isInfinite(inv_dotproduct) )
{
sum_weights += weights[ii][kk];
factor = inv_dotproduct*weights[ii][kk];
rangeDiff_s[kk] = rangeDiff_s[kk].binary( new Real( factor), Data.MULTIPLY,
sampling_mode, error_mode );
if ( first ) {
p_derivative = rangeDiff_s[kk];
first = false;
}
else {
p_derivative = p_derivative.binary( rangeDiff_s[kk], Data.ADD, sampling_mode,
error_mode );
}
}
}
Real real = new Real( d_partial_s[pp], sum_weights, D_units[ m_index] );
p_derivative = p_derivative.binary( real, Data.DIVIDE,
RangeType, sampling_mode, error_mode);
new_fields[pp].setSample( ii, p_derivative );
}
}
}
} //- missing range branch --*
if ( n_partials == 1 )
{
return new_fields[0];
}
else
{
return new Tuple( new_fields );
}
}
public Data derivative( int error_mode )
throws VisADException, RemoteException
{
MathType[] derivType_s = null;
RealType[] d_partial_s = null;
return this.derivative( null, d_partial_s, derivType_s, error_mode );
}
public Data derivative( MathType[] derivType_s, int error_mode )
throws VisADException, RemoteException
{
return this.derivative( null, null, derivType_s, error_mode );
}
public Function derivative( RealType d_partial, int error_mode )
throws VisADException, RemoteException
{
MathType[] derivType_s = null;
RealType[] d_partial_s = new RealType[1];
d_partial_s[0] = d_partial;
return (Function) this.derivative( null, d_partial_s, derivType_s, error_mode );
}
public Function derivative( RealType d_partial, MathType derivType, int error_mode)
throws VisADException, RemoteException
{
MathType[] derivType_s = new MathType[1];
RealType[] d_partial_s = new RealType[1];
derivType_s[0] = derivType;
d_partial_s[0] = d_partial;
return (Function) this.derivative( null, d_partial_s, derivType_s, error_mode );
}
/**
* Resample range values of this Field to domain samples in set either
* byt nearest neighbor or multi-linear interpolation.
* NOTE: this code is very similar to resample in FlatField.java
* @param set finite sampling values for the function.
* @param sampling_mode type of interpolation to perform (e.g.,
* Data.WEIGHTED_AVERAGE, Data.NEAREST_NEIGHBOR)
* @param error_mode type of error estimation to perform (e.g.,
* Data.INDEPENDENT, Data.DEPENDENT, Data.NO_ERRORS)
* @return Data object corresponding to the function value at that domain,
* using the sampling_mode and error_modes specified. NOTE: may
* return this (i.e., not a copy).
* @throws VisADException unable to resample function
* @throws RemoteException Java RMI exception
*/
public Field resample(Set set, int sampling_mode, int error_mode)
throws VisADException, RemoteException {
/* NB: resampling is done in this method for a float domain. If
* you make changes to this method, make the corresponding changes
* in resampleDouble if necessary.
*/
Set domainSet = getDomainSet();
if (domainSet.equals(set)) {
// nothing to do
return this;
}
MathType range_type = ((FunctionType) Type).getRange();
RealTupleType domain_type = ((SetType) set.getType()).getDomain();
FunctionType func_type = new FunctionType(domain_type, range_type);
Field field = new FieldImpl(func_type, set);
// Field field = new FieldImpl((FunctionType) Type, set);
if (isMissing()) return field;
int dim = domainSet.getDimension();
if (dim != set.getDimension()) {
throw new SetException("FieldImpl.resample: bad Set Dimension");
}
// Resampling in this method is done if floats so if we have
// a double domain, call resampleDouble.
if (domainSet instanceof GriddedDoubleSet) {
return resampleDouble(set, sampling_mode, error_mode);
}
CoordinateSystem coord_sys = set.getCoordinateSystem();
Unit[] units = set.getSetUnits();
ErrorEstimate[] errors =
(error_mode == NO_ERRORS) ? new ErrorEstimate[dim] : set.getSetErrors();
// create an array containing all indices of 'this'
int length = set.getLength();
int[] wedge = set.getWedge();
// array of Data objects to receive resampled Range objects
Data[] range = new Data[length];
// get values from wedge and possibly transform coordinates
float[][] vals = set.indexToValue(wedge);
// holder for sampling errors of transformed set - these are
// only useful to help estmate range errors due to resampling
ErrorEstimate[] errors_out = new ErrorEstimate[dim];
float[][] oldvals = vals;
try { // this is only to throw a more meaningful message
vals = CoordinateSystem.transformCoordinates(
((FunctionType) Type).getDomain(),
getDomainCoordinateSystem(),
getDomainUnits(), errors_out,
((SetType) set.getType()).getDomain(), coord_sys,
units, errors, vals);
} catch (UnitException ue) {
throw new VisADException("Sampling set is not compatible with domain");
}
boolean coord_transform = !(vals == oldvals);
// check whether we need to do sampling error calculations
boolean sampling_errors = (error_mode != NO_ERRORS);
if (sampling_errors) {
for (int i=0; i<dim; i++) {
if (errors_out[i] == null) sampling_errors = false;
}
}
Data[] sampling_partials = new Data[dim];
float[][] error_values;
double[] means = new double[dim];
Data[]Range = getRange ();
if (sampling_mode == WEIGHTED_AVERAGE && domainSet instanceof SimpleSet) {
// resample by interpolation
int[][] indices = new int[length][];
float[][] coefs = new float[length][];
((SimpleSet) domainSet).valueToInterp(vals, indices, coefs);
for (int i=0; i<length; i++) {
int len;
len = (indices[i] == null) ? 0 : indices[i].length;
if (len > 0) {
Data r = null;
// WLH
for (int k=0; k<len; k++) {
Data RangeIK;
synchronized (RangeLock) {
RangeIK = Range[indices[i][k]];
}
if (RangeIK != null) {
r = (r == null) ? RangeIK.multiply(new Real(coefs[i][k])) :
r.add(RangeIK.multiply(new Real(coefs[i][k])));
}
else {
r = null;
break;
}
}
// SRE 2002-02-13
if (r != null) {
r = r.changeMathType(((FunctionType)Type).getRange());
}
range[wedge[i]] = r;
}
else {
// set range[wedge[i]] to a missing Data object
range[wedge[i]] = ((FunctionType) Type).getRange().missingData();
}
if (sampling_errors && !range[wedge[i]].isMissing()) {
for (int j=0; j<dim; j++) means[j] = vals[j][i];
error_values = Set.doubleToFloat(
ErrorEstimate.init_error_values(errors_out, means) );
int[][] error_indices = new int[2 * dim][];
float[][] error_coefs = new float[2 * dim][];
coefs = new float[2 * dim][];
((SimpleSet) domainSet).valueToInterp(error_values, error_indices,
error_coefs);
for (int j=0; j<dim; j++) {
Data a = null;
Data b = null;
len = error_indices[2*j].length;
if (len > 0) {
for (int k=0; k<len; k++) {
Data RangeIK;
synchronized (RangeLock) {
RangeIK = Range[error_indices[2*j][k]];
}
if (RangeIK != null) {
a = (a == null) ?
RangeIK.multiply(new Real(error_coefs[2*j][k])) :
a.add(RangeIK.multiply(new Real(error_coefs[2*j][k])));
}
else {
a = null;
break;
}
}
}
len = error_indices[2*j+1].length;
if (len > 0) {
for (int k=0; k<len; k++) {
Data RangeIK;
synchronized (RangeLock) {
RangeIK = Range[error_indices[2*j+1][k]];
}
if (RangeIK != null) {
b = (b == null) ?
RangeIK.multiply(new Real(error_coefs[2*j+1][k])) :
b.add(RangeIK.multiply(new Real(error_coefs[2*j+1][k])));
}
else {
b = null;
break;
}
}
}
if (a == null || b == null) {
sampling_partials[j] = null;
}
else {
sampling_partials[j] = b.subtract(a).abs();
}
}
Data error = null;
if (error_mode == Data.INDEPENDENT) {
for (int j=0; j<dim; j++) {
Data e = sampling_partials[j].multiply(sampling_partials[j]);
error = (error == null) ? e : error.add(e);
}
error = error.sqrt();
}
else { // error_mode == Data.DEPENDENT
for (int j=0; j<dim; j++) {
Data e = sampling_partials[j];
error = (error == null) ? e : error.add(e);
}
}
range[wedge[i]] =
range[wedge[i]].adjustSamplingError(error, error_mode);
} // end if (sampling_errors && !range[wedge[i]].isMissing())
} // end for (int i=0; i<length; i++)
}
else { // Mode is NEAREST_NEIGHBOR or set is not GriddedSet
// simple resampling
int[] indices = domainSet.valueToIndex(vals);
for (int i=0; i<length; i++) {
synchronized (RangeLock) {
range[wedge[i]] = (indices[i] >= 0 && Range[indices[i]] != null) ?
Range[indices[i]] :
((FunctionType) Type).getRange().missingData();
}
if (sampling_errors && !range[wedge[i]].isMissing()) {
for (int j=0; j<dim; j++) means[j] = vals[j][i];
error_values = Set.doubleToFloat(
ErrorEstimate.init_error_values(errors_out, means) );
int[] error_indices = domainSet.valueToIndex(error_values);
for (int j=0; j<dim; j++) {
synchronized (RangeLock) {
if (error_indices[2*j] < 0 || Range[error_indices[2*j]] == null ||
error_indices[2*j+1] < 0 || Range[error_indices[2*j+1]] == null) {
sampling_partials[j] = null;
}
else {
sampling_partials[j] = Range[error_indices[2*j+1]].
subtract(Range[error_indices[2*j]]).abs();
}
}
}
Data error = null;
if (error_mode == Data.INDEPENDENT) {
for (int j=0; j<dim; j++) {
Data e = sampling_partials[j].multiply(sampling_partials[j]);
error = (error == null) ? e : error.add(e);
}
error = error.sqrt();
}
else { // error_mode == Data.DEPENDENT
for (int j=0; j<dim; j++) {
Data e = sampling_partials[j];
error = (error == null) ? e : error.add(e);
}
}
range[wedge[i]] =
range[wedge[i]].adjustSamplingError(error, error_mode);
} // end if (sampling_errors && !range[wedge[i]].isMissing())
} // end for (int i=0; i<length; i++)
}
if (coord_transform) {
// domain coordinates were transformed, so make corresponding
// vector transform to any RealVectorType-s in range
MathType RangeType = ((FunctionType) Type).getRange();
if (RangeType instanceof RealVectorType) {
int n = vals.length;
float[][] inloc = new float[n][1];
float[][] outloc = new float[n][1];
for (int i=0; i<length; i++) {
for (int k=0; k<n; k++) inloc[k][0] = oldvals[k][i];
for (int k=0; k<n; k++) outloc[k][0] = vals[k][i];
range[i] = ((RealVectorType) RangeType).transformVectors(
((FunctionType) Type).getDomain(),
getDomainCoordinateSystem(), getDomainUnits(), errors_out,
((SetType) set.getType()).getDomain(),
coord_sys, units,
((RealTuple) range[i]).getCoordinateSystem(),
inloc, outloc, (RealTuple) range[i]);
}
}
else if (RangeType instanceof TupleType &&
!(RangeType instanceof RealTupleType)) {
int m = ((TupleType) RangeType).getDimension();
boolean any_vector = false;
for (int j=0; j<m; j++) {
if (((TupleType) RangeType).getComponent(j) instanceof RealVectorType) {
any_vector = true;
}
}
if (any_vector) {
int n = vals.length;
float[][] inloc = new float[n][1];
float[][] outloc = new float[n][1];
Data[] datums = new Data[m];
for (int i=0; i<length; i++) {
for (int k=0; k<n; k++) inloc[k][0] = oldvals[k][i];
for (int k=0; k<n; k++) outloc[k][0] = vals[k][i];
for (int j=0; j<m; j++) {
MathType comp_type = ((TupleType) RangeType).getComponent(j);
if (comp_type instanceof RealVectorType) {
RealTuple component =
(RealTuple) ((TupleIface) range[i]).getComponent(j);
datums[j] = ((RealVectorType) comp_type).transformVectors(
((FunctionType) Type).getDomain(),
getDomainCoordinateSystem(), getDomainUnits(), errors_out,
((SetType) set.getType()).getDomain(),
coord_sys, units, component.getCoordinateSystem(),
inloc, outloc, component);
}
else {
datums[j] = ((TupleIface) range[i]).getComponent(j);
}
}
range[i] = new Tuple(datums);
}
}
}
} // end if (coord_transform)
((FieldImpl)field).setSamples(range, false, false);
return field;
}
/**
* Resample range values of this Field to domain samples in set either
* byt nearest neighbor or multi-linear interpolation.
* NOTE: this code is very similar to resample in FlatField.java
* @param set finite sampling values for the function.
* @param sampling_mode type of interpolation to perform (e.g.,
* Data.WEIGHTED_AVERAGE, Data.NEAREST_NEIGHBOR)
* @param error_mode type of error estimation to perform (e.g.,
* Data.INDEPENDENT, Data.DEPENDENT, Data.NO_ERRORS)
* @return Data object corresponding to the function value at that domain,
* using the sampling_mode and error_modes specified. NOTE: may
* return this (i.e., not a copy).
* @throws VisADException unable to resample function
* @throws RemoteException Java RMI exception
*/
public Field resampleDouble(Set set, int sampling_mode, int error_mode)
throws VisADException, RemoteException {
/* NB: resampling is done in this method for a double domain. If
* you make changes to this method, make the corresponding changes
* in resample if necessary.
*/
Set domainSet = getDomainSet();
if (domainSet.equals(set)) {
// nothing to do
return this;
}
MathType range_type = ((FunctionType) Type).getRange();
RealTupleType domain_type = ((SetType) set.getType()).getDomain();
FunctionType func_type = new FunctionType(domain_type, range_type);
Field field = new FieldImpl(func_type, set);
// Field field = new FieldImpl((FunctionType) Type, set);
if (isMissing()) return field;
int dim = domainSet.getDimension();
if (dim != set.getDimension()) {
throw new SetException("FieldImpl.resample: bad Set Dimension");
}
if (!(domainSet instanceof GriddedDoubleSet)) {
return resample(set, sampling_mode, error_mode);
}
CoordinateSystem coord_sys = set.getCoordinateSystem();
Unit[] units = set.getSetUnits();
ErrorEstimate[] errors =
(error_mode == NO_ERRORS) ? new ErrorEstimate[dim] : set.getSetErrors();
// create an array containing all indices of 'this'
int length = set.getLength();
int[] wedge = set.getWedge();
// array of Data objects to receive resampled Range objects
Data[] range = new Data[length];
// get values from wedge and possibly transform coordinates
double[][] vals = set.indexToDouble(wedge);
// holder for sampling errors of transformed set - these are
// only useful to help estmate range errors due to resampling
ErrorEstimate[] errors_out = new ErrorEstimate[dim];
double[][] oldvals = vals;
try { // this is only to throw a more meaningful message
vals = CoordinateSystem.transformCoordinates(
((FunctionType) Type).getDomain(),
getDomainCoordinateSystem(),
getDomainUnits(), errors_out,
((SetType) set.getType()).getDomain(), coord_sys,
units, errors, vals);
} catch (UnitException ue) {
throw new VisADException("Sampling set is not compatible with domain");
}
boolean coord_transform = !(vals == oldvals);
// check whether we need to do sampling error calculations
boolean sampling_errors = (error_mode != NO_ERRORS);
if (sampling_errors) {
for (int i=0; i<dim; i++) {
if (errors_out[i] == null) sampling_errors = false;
}
}
Data[] sampling_partials = new Data[dim];
double[][] error_values;
double[] means = new double[dim];
Data[]Range = getRange ();
if (sampling_mode == WEIGHTED_AVERAGE) {
// resample by interpolation
int[][] indices = new int[length][];
double[][] coefs = new double[length][];
((GriddedDoubleSet) domainSet).doubleToInterp(vals, indices, coefs);
for (int i=0; i<length; i++) {
int len;
len = (indices[i] == null) ? 0 : indices[i].length;
if (len > 0) {
Data r = null;
// WLH
for (int k=0; k<len; k++) {
Data RangeIK;
synchronized (RangeLock) {
RangeIK = Range[indices[i][k]];
}
if (RangeIK != null) {
r = (r == null) ? RangeIK.multiply(new Real(coefs[i][k])) :
r.add(RangeIK.multiply(new Real(coefs[i][k])));
}
else {
r = null;
break;
}
}
// SRE 2002-02-13
if (r != null) {
r = r.changeMathType(((FunctionType)Type).getRange());
}
range[wedge[i]] = r;
}
else {
// set range[wedge[i]] to a missing Data object
range[wedge[i]] = ((FunctionType) Type).getRange().missingData();
}
if (sampling_errors && !range[wedge[i]].isMissing()) {
for (int j=0; j<dim; j++) means[j] = vals[j][i];
error_values = ErrorEstimate.init_error_values(errors_out, means);
int[][] error_indices = new int[2 * dim][];
double[][] error_coefs = new double[2 * dim][];
coefs = new double[2 * dim][];
((GriddedDoubleSet) domainSet).doubleToInterp(error_values, error_indices,
error_coefs);
for (int j=0; j<dim; j++) {
Data a = null;
Data b = null;
len = error_indices[2*j].length;
if (len > 0) {
for (int k=0; k<len; k++) {
Data RangeIK;
synchronized (RangeLock) {
RangeIK = Range[error_indices[2*j][k]];
}
if (RangeIK != null) {
a = (a == null) ?
RangeIK.multiply(new Real(error_coefs[2*j][k])) :
a.add(RangeIK.multiply(new Real(error_coefs[2*j][k])));
}
else {
a = null;
break;
}
}
}
len = error_indices[2*j+1].length;
if (len > 0) {
for (int k=0; k<len; k++) {
Data RangeIK;
synchronized (RangeLock) {
RangeIK = Range[error_indices[2*j+1][k]];
}
if (RangeIK != null) {
b = (b == null) ?
RangeIK.multiply(new Real(error_coefs[2*j+1][k])) :
b.add(RangeIK.multiply(new Real(error_coefs[2*j+1][k])));
}
else {
b = null;
break;
}
}
}
if (a == null || b == null) {
sampling_partials[j] = null;
}
else {
sampling_partials[j] = b.subtract(a).abs();
}
}
Data error = null;
if (error_mode == Data.INDEPENDENT) {
for (int j=0; j<dim; j++) {
Data e = sampling_partials[j].multiply(sampling_partials[j]);
error = (error == null) ? e : error.add(e);
}
error = error.sqrt();
}
else { // error_mode == Data.DEPENDENT
for (int j=0; j<dim; j++) {
Data e = sampling_partials[j];
error = (error == null) ? e : error.add(e);
}
}
range[wedge[i]] =
range[wedge[i]].adjustSamplingError(error, error_mode);
} // end if (sampling_errors && !range[wedge[i]].isMissing())
} // end for (int i=0; i<length; i++)
}
else { // Mode is NEAREST_NEIGHBOR or set is not GriddedSet
// simple resampling
int[] indices = domainSet.doubleToIndex(vals);
for (int i=0; i<length; i++) {
synchronized (RangeLock) {
range[wedge[i]] = (indices[i] >= 0 && Range[indices[i]] != null) ?
Range[indices[i]] :
((FunctionType) Type).getRange().missingData();
}
if (sampling_errors && !range[wedge[i]].isMissing()) {
for (int j=0; j<dim; j++) means[j] = vals[j][i];
error_values = ErrorEstimate.init_error_values(errors_out, means);
int[] error_indices = domainSet.doubleToIndex(error_values);
for (int j=0; j<dim; j++) {
synchronized (RangeLock) {
if (error_indices[2*j] < 0 || Range[error_indices[2*j]] == null ||
error_indices[2*j+1] < 0 || Range[error_indices[2*j+1]] == null) {
sampling_partials[j] = null;
}
else {
sampling_partials[j] = Range[error_indices[2*j+1]].
subtract(Range[error_indices[2*j]]).abs();
}
}
}
Data error = null;
if (error_mode == Data.INDEPENDENT) {
for (int j=0; j<dim; j++) {
Data e = sampling_partials[j].multiply(sampling_partials[j]);
error = (error == null) ? e : error.add(e);
}
error = error.sqrt();
}
else { // error_mode == Data.DEPENDENT
for (int j=0; j<dim; j++) {
Data e = sampling_partials[j];
error = (error == null) ? e : error.add(e);
}
}
range[wedge[i]] =
range[wedge[i]].adjustSamplingError(error, error_mode);
} // end if (sampling_errors && !range[wedge[i]].isMissing())
} // end for (int i=0; i<length; i++)
}
if (coord_transform) {
// domain coordinates were transformed, so make corresponding
// vector transform to any RealVectorType-s in range
MathType RangeType = ((FunctionType) Type).getRange();
if (RangeType instanceof RealVectorType) {
int n = vals.length;
double[][] inloc = new double[n][1];
double[][] outloc = new double[n][1];
for (int i=0; i<length; i++) {
for (int k=0; k<n; k++) inloc[k][0] = oldvals[k][i];
for (int k=0; k<n; k++) outloc[k][0] = vals[k][i];
range[i] = ((RealVectorType) RangeType).transformVectors(
((FunctionType) Type).getDomain(),
getDomainCoordinateSystem(), getDomainUnits(), errors_out,
((SetType) set.getType()).getDomain(),
coord_sys, units,
((RealTuple) range[i]).getCoordinateSystem(),
inloc, outloc, (RealTuple) range[i]);
}
}
else if (RangeType instanceof TupleType &&
!(RangeType instanceof RealTupleType)) {
int m = ((TupleType) RangeType).getDimension();
boolean any_vector = false;
for (int j=0; j<m; j++) {
if (((TupleType) RangeType).getComponent(j) instanceof RealVectorType) {
any_vector = true;
}
}
if (any_vector) {
int n = vals.length;
double[][] inloc = new double[n][1];
double[][] outloc = new double[n][1];
Data[] datums = new Data[m];
for (int i=0; i<length; i++) {
for (int k=0; k<n; k++) inloc[k][0] = oldvals[k][i];
for (int k=0; k<n; k++) outloc[k][0] = vals[k][i];
for (int j=0; j<m; j++) {
MathType comp_type = ((TupleType) RangeType).getComponent(j);
if (comp_type instanceof RealVectorType) {
RealTuple component =
(RealTuple) ((TupleIface) range[i]).getComponent(j);
datums[j] = ((RealVectorType) comp_type).transformVectors(
((FunctionType) Type).getDomain(),
getDomainCoordinateSystem(), getDomainUnits(), errors_out,
((SetType) set.getType()).getDomain(),
coord_sys, units, component.getCoordinateSystem(),
inloc, outloc, component);
}
else {
datums[j] = ((TupleIface) range[i]).getComponent(j);
}
}
range[i] = new Tuple(datums);
}
}
}
} // end if (coord_transform)
((FieldImpl)field).setSamples(range, false, false);
return field;
}
public DataShadow computeRanges(ShadowType type, DataShadow shadow)
throws VisADException, RemoteException {
if (isMissing()) return shadow;
ShadowRealTupleType domain_type = ((ShadowFunctionType) type).getDomain();
int n = domain_type.getDimension();
double[][] ranges = new double[2][n];
// DomainSet.computeRanges handles Reference
shadow = getDomainSet().computeRanges(domain_type, shadow, ranges, true);
ShadowType rtype = ((ShadowFunctionType) type).getRange();
if (MyRange != null) {
for (int i=0; i<MyRange.length; i++) {
synchronized (RangeLock) {
if (MyRange[i] != null) shadow = MyRange[i].computeRanges(rtype, shadow);
}
}
}
return shadow;
}
/** return a Field that clones this, except its ErrorEstimate-s
are adjusted for sampling errors in error */
public Data adjustSamplingError(Data error, int error_mode)
throws VisADException, RemoteException {
if (isMissing() || error == null || error.isMissing()) return this;
Field field = new FieldImpl((FunctionType) Type, getDomainSet());
if (isMissing()) return field;
Field new_error =
((Field) error).resample(getDomainSet(), NEAREST_NEIGHBOR, NO_ERRORS);
//Only do this if we have a MyRange
Data[] range = new Data[getLength()];
for (int i=0; i<getLength(); i++) {
synchronized (RangeLock) {
if (MyRange != null && MyRange[i] != null) {
range[i] = MyRange[i].adjustSamplingError(new_error.getSample(i), error_mode);
} else {
range[i]=null;
}
}
}
field.setSamples(range, true);
return field;
}
public boolean isFlatField() {
return false;
}
/**
* A wrapper around {@link #getLength() getLength} for JPython.
*/
public int __len__() throws VisADException, RemoteException {
return getLength();
}
/**
* A wrapper around {@link #getSample(int) getSample} for JPython.
*/
public Data __getitem__(int index) throws VisADException, RemoteException {
return getSample(index);
}
/**
* A wrapper around {@link #setSample(int, Data) setSample} for JPython.
*/
public void __setitem__(int index, Data data)
throws VisADException, RemoteException {
if (data instanceof Real && ( (Real)data).getUnit() == null) {
__setitem__(index, ( (Real)data).getValue());
} else {
setSample(index, data);
}
}
/**
* A wrapper around {@link #setSample(int, Data) setSample} for JPython.
*/
public void __setitem__(int index, double data)
throws VisADException, RemoteException {
RealType real = null;
boolean tuple = false;
MathType range = ((FunctionType) getType()).getRange();
if (range instanceof RealType) {
real = (RealType) range;
}
else if (range instanceof RealTupleType) {
if (((RealTupleType) range).getDimension() == 1) {
real = (RealType) ((RealTupleType) range).getComponent(0);
tuple = true;
}
}
if (real != null) {
Real r = new Real(real, data);
if (tuple) {
setSample(index, new RealTuple(new Real[] {r}));
}
else {
setSample(index, r);
}
}
else {
System.out.println("FieldImpl.__setitem__ bad type");
}
}
/**
* <p>Clones this instance. The {@link MathType}, domain {@link Set}, and
* {@link CoordinateSystem} are shallow copied. Each range value, however,
* has its <code>clone()</code> method invoked.</p>
*
* <p> Note that it is possible to simultaneously modify the domain-set of
* both this instance and the clone by modifying the values in the array
* returned by invoking <code>getSamples(false)</code> on the domain-set of
* either this instance or the clone. Don't do this unless you enjoy
* debugging.</p>
*
* @return A clone of this instance.
* @throws CloneNotSupportedException if cloning isn't supported by a
* range-value.
*/
public Object clone() throws CloneNotSupportedException {
FieldImpl clone = (FieldImpl)super.clone();
synchronized(RangeLock) {
if (MyRange != null) {
clone.MyRange = new Data[MyRange.length];
for (int i = 0; i < MyRange.length; i++) {
if (MyRange[i] != null) {
try {
/*
* Data.dataClone() is invoked because
* Data.clone() doesn't and can't exist.
*/
clone.MyRange[i] = (Data)MyRange[i].dataClone();
}
catch (RemoteException ex) {
throw new RuntimeException(ex.toString());
}
}
}
}
}
return clone;
}
public String longString(String pre)
throws VisADException, RemoteException {
StringBuffer s = new StringBuffer(pre + "FieldImpl\n" + pre + " Type: " +
Type.toString() + "\n");
Set domainSet = getDomainSet();
if (domainSet != null) {
s.append(pre + " DomainSet:\n" + domainSet.longString(pre + " "));
}
else {
s.append(pre + " DomainSet: undefined\n");
}
if (isMissing()) {
s.append(" missing\n");
return s.toString();
}
if (MyRange !=null) {
for (int i=0; i<getLength(); i++) {
s.append(pre + " Range value " + i + ":\n" + ((MyRange[i] == null) ?
(pre + "missing\n") : MyRange[i].longString(pre + " ")));
}
}
return s.toString();
}
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof FieldImpl)) {
return false;
}
FieldImpl fi = (FieldImpl )obj;
if (!getType().equals(fi.getType())) {
return false;
}
if (getLength() != fi.getLength()) {
return false;
}
if (MissingFlag != fi.MissingFlag) {
return false;
}
Set domainSet = getDomainSet();
if (domainSet == null || fi.getDomainSet() == null) {
if (domainSet != null || fi.getDomainSet() != null) {
return false;
}
} else {
if (!domainSet.equals(fi.getDomainSet())) {
return false;
}
}
return true;
}
/**
<PRE>
Here's how to use this:
for (Enumeration e = field.domainEnumeration() ; e.hasMoreElements(); ) {
RealTuple domain_sample = (RealTuple) e.nextElement();
Data range = field.evaluate(domain_sample);
}
</PRE>
*/
public Enumeration domainEnumeration()
throws VisADException, RemoteException {
return new FieldEnumerator(this);
}
}
class FieldEnumerator implements Enumeration {
Field field;
int[] index;
int dimension;
RealTupleType type;
CoordinateSystem coordinateSystem;
RealType[] types;
Unit[] units;
FieldEnumerator(Field f) throws VisADException, RemoteException {
field = f;
if (field.getDomainSet() == null) {
throw new FieldException("FieldImplEnumerator: DomainSet undefined");
}
index = new int[1];
index[0] = 0;
dimension = field.getDomainSet().getDimension();
type = ((FunctionType) field.getType()).getDomain();
/*
* The setting of the CoordinateSytem is non-trivial because a the default
* CoordinateSystem of the domain of a FieldImpl can be null while the
* CoordinateSystem of the domain set of the FieldImpl can be non-null --
* giving rise to the possibility of returning a domain RealTuple with a
* non-null CoordinateSystem even though the corresponding RealTupleType
* doesn't have one. (see nextElement() below.)
*/
coordinateSystem = type.getCoordinateSystem();
if (coordinateSystem != null)
coordinateSystem = field.getDomainCoordinateSystem();
types = new RealType[dimension];
units = field.getDomainUnits();
for (int j=0; j<dimension; j++) {
types[j] = (RealType) type.getComponent(j);
}
}
public boolean hasMoreElements() {
try {
return index[0] < field.getLength();
}
catch (RemoteException e) {
return false;
}
catch (VisADException e) {
return false;
}
}
/*
* According to the semantics for java.util.Enumeration, this method can only
* throw a NoSuchElementException; consequently, all other exceptions must be
* trapped and converted.
*/
public Object nextElement() throws NoSuchElementException {
try {
if (index[0] < field.getLength()) {
float[][] vals = field.getDomainSet().indexToValue(index);
index[0]++;
Real[] reals = new Real[dimension];
for (int j=0; j<dimension; j++) {
reals[j] = new Real(types[j], (double) vals[j][0], units[j]);
}
/*
* The actual CoordinateSystem of the domain set is used only if the
* domain's RealTupleType has a non-null CoordinateSystem; otherwise,
* an exception would be thrown as of version 1.34.
*/
return new RealTuple(type, reals, coordinateSystem);
}
else {
throw new NoSuchElementException(
"FieldImplEnumerator.nextElement: no more elements");
}
}
catch (VisADException e) {
throw new NoSuchElementException("FieldImplEnumerator.nextElement: " + e);
}
catch (RemoteException e) {
throw new NoSuchElementException("FieldImplEnumerator.nextElement: " + e);
}
}
}
/**
class NDhelper
{
int n_dims;
int d = 0;
int cnt = 0;
int[] lengths;
int[] dim_product;
int[] sub_domain;
int[] indexes;
int[][] all;
int[] work;
int product;
NDhelper( int[] lengths, int[] dim_product, int[] sub_domain )
{
this.lengths = lengths;
this.n_dims = lengths.length;
this.indexes = new int[ n_dims ];
this.dim_product = dim_product;
this.sub_domain = sub_domain;
product = 1;
for ( int i = 0; i < n_dims; i++ ) {
product *= lengths[i];
}
work = new int[product];
permute();
}
void permute()
{
if ( d == indexes.length )
{
work[cnt] = 0;
for ( int k = 0; k < indexes.length; k++ ) {
work[cnt] += dim_product[sub_domain[k]]*indexes[(n_dims-1) - k];
}
cnt++;
}
else
{
for ( int i = 0; i < lengths[(n_dims-1) - d]; i++ )
{
indexes[d] = i;
d++;
permute();
d--;
}
}
}
public int[] getPermutations()
{
return work;
}
void permute()
{
for ( int k = 0; k < product; k++ )
{
int k2 = k;
for ( int j = (n_dims-1); j == 0; j-- ) {
int temp = 1;
for ( int m = 0; m < j; m++ ) {
temp *= lengths[m];
}
indexes[j] = k2/temp;
k2 -= temp*indexes[j];
}
for ( int t = 0; t < indexes.length; t++ ) {
work[k] += dim_product[sub_domain[t]]*indexes[(n_dims-1) - t];
}
}
}
}
**/