//
// RealTuple.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.*;
/**
RealTuple is the VisAD data class for vectors in R^n for n>0.
RealTuple objects are immutable.<P>
*/
public class RealTuple
extends Tuple
implements RealTupleIface
{
private CoordinateSystem TupleCoordinateSystem;
private boolean checkRealUnits;
/*
* Simply copies of Unit-s from Real tupleComponents.
* Will be null if RealTuple(RealTupleType) constructor is used.
*/
private Unit[] TupleUnits = null;
/**
* construct a RealTuple object with the missing value
* @param type RealTupleType of this RealTuple
*/
public RealTuple(RealTupleType type) {
super(type);
TupleCoordinateSystem = type.getCoordinateSystem();
if (tupleComponents != null) {
int n = tupleComponents.length;
TupleUnits = new Unit[n];
for (int i=0; i<n; i++) TupleUnits[i] = null;
}
}
/**
* construct a RealTuple according to an array of Real objects;
* coordinate_system may be null; otherwise coordinate_system.getReference()
* must equal type.getCoordinateSystem.getReference()
*
* @param type RealTupleType of this RealTuple
* @param reals array of reals
* @param coord_sys CoordinateSystem for this RealTuple
*/
public RealTuple(RealTupleType type, Real[] reals, CoordinateSystem coord_sys)
throws VisADException, RemoteException {
this(type, reals, coord_sys, null, true);
}
/**
* Construct a RealTuple according to an array of Real objects;
* coordinate_system may be null; otherwise coordinate_system.getReference()
* must equal type.getCoordinateSystem.getReference()
*
* @param type RealTupleType of this RealTuple
* @param reals array of reals
* @param coord_sys CoordinateSystem for this RealTuple
* @param units array of Units corresponding to the array of Reals.
* @param checkUnits true to make sure the units of the Reals are convertible
* with the RealType units. <b>NB: setting this to false
* can cause problems if the units are not convertible.
* Only do this if you know what you are doing.</b>
*/
public RealTuple(RealTupleType type, Real[] reals, CoordinateSystem coord_sys,
Unit[] units, boolean checkUnits)
throws VisADException, RemoteException {
super(type, reals, false); // copy == false because Reals are immutable
TupleUnits = units;
checkRealUnits = checkUnits;
init_coord_sys(coord_sys);
}
/**
* construct a RealTuple according to an array of Real objects
* @param reals array of reals
*/
public RealTuple(Real[] reals)
throws VisADException, RemoteException {
this((RealTupleType)buildTupleType(reals), reals, null,
buildTupleUnits(reals), false);
}
/**
* Construct a RealTuple according to a RealTupleType and a double array
* @param type RealTupleType of this RealTuple
* @param values values for each component. Units are the default units
* of the RealTupleType components.
*/
public RealTuple(RealTupleType type, double[] values)
throws VisADException, RemoteException {
this(type, buildRealArray(type, values), null, type.getDefaultUnits(), false);
}
/** initialize TupleCoordinateSystem and TupleUnits */
private void init_coord_sys(CoordinateSystem coord_sys)
throws VisADException {
CoordinateSystem cs = ((RealTupleType) Type).getCoordinateSystem();
if (coord_sys == null) {
TupleCoordinateSystem = cs;
}
else {
if (cs == null || !cs.getReference().equals(coord_sys.getReference())) {
throw new CoordinateSystemException("RealTuple: coord_sys " +
coord_sys.getReference() +
" must match" +
" Type.DefaultCoordinateSystem " +
(cs == null ? null :
cs.getReference()));
}
TupleCoordinateSystem = coord_sys;
}
if (TupleCoordinateSystem != null &&
!Unit.canConvertArray(TupleCoordinateSystem.getCoordinateSystemUnits(),
((RealTupleType) Type).getDefaultUnits())) {
throw new UnitException("RealTuple: CoordinateSystem Units must be " +
"convertable with Type default Units");
}
if (TupleUnits == null) {
int n = tupleComponents.length;
TupleUnits = new Unit[n];
for (int i=0; i<n; i++) {
TupleUnits[i] = ((Real) tupleComponents[i]).getUnit();
}
}
if (checkRealUnits) {
if(!Unit.canConvertArray(TupleUnits,
((RealTupleType) Type).getDefaultUnits())) {
throw new UnitException("Tuple: Units must be convertable with " +
"Type default Units");
}
}
if(TupleCoordinateSystem != null &&
!Unit.canConvertArray(TupleCoordinateSystem.getCoordinateSystemUnits(),
TupleUnits)) {
throw new UnitException("Tuple: Units must be convertable with " +
"CoordinateSystem Units");
}
}
private static Real[] buildRealArray(RealTupleType type, double[] values)
throws VisADException {
Real[] reals = new Real[values.length];
for (int i=0; i<values.length; i++) {
reals[i] = new Real((RealType) type.getComponent(i), values[i]);
}
return reals;
}
private static Unit[] buildTupleUnits(Real[] reals) throws VisADException {
if (reals == null || reals.length == 0) return (Unit[]) null;
int n = reals.length;
Unit[] units = new Unit[reals.length];
for (int i=0; i<n; i++) units[i] = reals[i].getUnit();
return units;
}
/**
* Adds a listener for changes to this instance. Because instances of this
* class don't change, this method does nothing.
*
* @param listener The listener for changes.
*/
public final void addReference(ThingReference listener) {
}
/**
* Removes a listener for changes to this instance. Because instances of this
* class don't change, this method does nothing.
*
* @param listener The change listener to be removed.
*/
public final void removeReference(ThingReference listener) {
}
/**
* Get the values of the Real components
* @return double array of the values of each Real component
*/
public double[] getValues() {
int n = getDimension();
double[] values = new double[n];
Data[] tupleComps = getComponents(false);
for (int i=0; i<n; i++) values[i] = ((Real) tupleComps[i]).getValue();
return values;
}
/** get Units of Real components */
public Unit[] getTupleUnits() {
return Unit.copyUnitsArray(TupleUnits);
}
/** get ErrorEstimates of Real components */
public ErrorEstimate[] getErrors()
throws VisADException, RemoteException {
int n = getDimension();
ErrorEstimate[] errors = new ErrorEstimate[n];
for (int i=0; i<n; i++) errors[i] = ((Real) getComponent(i)).getError();
return errors;
}
/** get CoordinateSystem */
public CoordinateSystem getCoordinateSystem() {
return TupleCoordinateSystem;
}
/*- 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 {
/* BINARY - TDR May 28, 1998 */
MathType m_type;
if ( new_type == null ) {
throw new TypeException("binary: new_type may not be null" );
}
/* BINARY - end */
if (data instanceof RealTuple) {
if (!Type.equalsExceptName(data.getType())) {
throw new TypeException("RealTuple.binary: types don't match");
}
/*- TDR May 1998 */
if ( !Type.equalsExceptName(new_type) ) {
throw new TypeException("RealTuple.binary: new_type doesn't match return type");
}
/*- end */
if (isMissing() || data.isMissing()) {
return new RealTuple((RealTupleType) new_type);
}
int dim = getDimension();
double[][] vals = new double[dim][1];
for (int j=0; j<dim; j++) {
vals[j][0] = ((Real) ((RealTuple) data).getComponent(j)).getValue();
}
ErrorEstimate[] errors_out = new ErrorEstimate[dim];
vals = CoordinateSystem.transformCoordinates(
(RealTupleType) Type, getCoordinateSystem(),
getTupleUnits(), errors_out,
(RealTupleType) data.getType(),
((RealTuple) data).getCoordinateSystem(),
((RealTuple) data).getTupleUnits(),
((RealTuple) data).getErrors(), vals);
Real[] reals = new Real[dim];
Unit[] tupleUnits = getTupleUnits();
for (int j=0; j<dim; j++) {
Real real = new Real((RealType) ((RealTupleType) Type).getComponent(j),
vals[j][0], tupleUnits[j], errors_out[j]);
/*- TDR May 1998 */
m_type = ((RealTupleType)new_type).getComponent(j);
/*- end */
reals[j] =
/*- TDR May 1998
(Real) getComponent(j).binary(real, op, sampling_mode, error_mode);
*/
(Real) getComponent(j).binary(real, op, m_type, sampling_mode, error_mode);
}
/* BINARY - TDR May 28, 1998
return new RealTuple((RealTupleType)Type, reals, TupleCoordinateSystem);
*/
return new RealTuple((RealTupleType) new_type, reals, null );
}
else if (data instanceof TupleIface) {
throw new TypeException("RealTuple.binary: types don't match");
}
else if (data instanceof Real) {
if (isMissing() || data.isMissing()) {
return new RealTuple((RealTupleType) Type);
}
int dim = getDimension();
Real[] reals = new Real[dim];
for (int j=0; j<dim; j++) {
m_type = ((RealTupleType)new_type).getComponent(j);
/*- TDR May 1998
reals[j] = (Real) getComponent(j).binary(data, op, sampling_mode,
error_mode);
*/
reals[j] = (Real) getComponent(j).binary(data, op, m_type,
sampling_mode, error_mode);
}
/*- TDR May 1998
return new RealTuple((RealTupleType) Type, reals, TupleCoordinateSystem);
*/
return new RealTuple((RealTupleType) new_type, reals, null );
}
else if (data instanceof Field) {
/*- TDR June 3, 1998 */
if ( !(data.getType()).equalsExceptName(new_type) ) {
throw new TypeException();
}
return data.binary(this, invertOp(op), new_type, sampling_mode, error_mode);
/*- end */
}
else {
throw new TypeException("RealTuple.binary");
}
}
/*- 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");
}
RealTupleType RT_type= (RealTupleType)new_type;
if (isMissing()) return new RealTuple((RealTupleType) Type);
int dim = getDimension();
Real[] reals = new Real[dim];
for (int j=0; j<dim; j++) {
reals[j] = (Real) getComponent(j).unary(op, RT_type.getComponent(j),
sampling_mode, error_mode);
}
return new RealTuple((RealTupleType) new_type, reals, getCoordinateSystem());
}
public DataShadow computeRanges(ShadowType type, DataShadow shadow)
throws VisADException, RemoteException {
shadow = super.computeRanges(type, shadow);
ShadowRealTupleType shad_ref = ((ShadowRealTupleType) type).getReference();
if (isMissing() || shad_ref == null) return shadow;
int n = tupleComponents.length;
// computeRanges for Reference RealTypes
double[][] ranges = new double[2][n];
for (int i=0; i<n; i++) {
double value = ((Real) getComponent(i)).getValue();
// WLH 20 Nov 2001
Unit[] tupleUnits = getTupleUnits();
Unit unit =
((RealType) ((RealTupleType) Type).getComponent(i)).getDefaultUnit();
if (unit != null && !unit.equals(tupleUnits[i])) {
value = unit.toThis(value, tupleUnits[i]);
}
if (value != value) return shadow;
ranges[0][i] = value;
ranges[1][i] = value;
}
return computeReferenceRanges((ShadowRealTupleType) type,
// getCoordinateSystem(), getTupleUnits(),
getCoordinateSystem(),
((RealTupleType) Type).getDefaultUnits(),
shadow, shad_ref, ranges);
}
/**
* Clones this instance.
*
* @return A clone of this instance.
*/
public final Object clone() {
/*
* I (Steve Emmerson) believe that this implementation should return
* "this" to reduce the memory-footprint but Bill believes that doing so
* would be counter-intuitive and might harm applications.
*/
try {
return super.clone();
}
catch (CloneNotSupportedException ex) {
throw new RuntimeException("Assertion failure");
}
}
/**
* Provide a String representation of this RealTuple.
*/
public String toString() {
if (isMissing()) return "missing";
Data[] tupleComps = getComponents(false);
String s = "(" + tupleComps[0];
for (int i=1; i<getDimension(); i++) {
s = s + ", " + tupleComps[i];
}
return s + ")";
}
public String longString(String pre)
throws VisADException, RemoteException {
String s = pre + "RealTuple\n" + pre + " Type: " + Type.toString() + "\n";
if (isMissing()) return s + " missing\n";
for (int i=0; i<getDimension(); i++) {
s = s + pre + " Tuple Component " + i + ": Value = " +
((Real) getComponent(i)).getValue() + " (TypeName = " +
((RealType) getComponent(i).getType()).getName() + ")\n";
}
return s;
}
/** run 'java visad.RealTuple' to test the RealTuple class */
public static void main(String args[])
throws VisADException, RemoteException {
byte b = 10;
Real w = new Real(b);
Real[] reals1 = {new Real(1), new Real(2), new Real(3)};
RealTuple rt1 = new RealTuple(reals1);
Real[] reals2 = {new Real(6), new Real(5), new Real(4)};
RealTuple rt2 = new RealTuple(reals2);
System.out.println("rt1 = " + rt1 + "\nrt2 = " + rt2);
System.out.println("rt1 + rt2 = " + rt1.add(rt2));
System.out.println("rt1 - rt2 = " + rt1.subtract(rt2));
System.out.println("rt1 * rt2 = " + rt1.multiply(rt2));
System.out.println("rt1 / rt2 = " + rt1.divide(rt2));
System.out.println("sqrt(rt1) = " + rt1.sqrt());
System.out.println("rt1 + w = " + rt1.add(w));
System.out.println("rt1 - w = " + rt1.subtract(w));
System.out.println("rt1 * w = " + rt1.multiply(w));
System.out.println("rt1 / w = " + rt1.divide(w));
System.out.println("w + rt2 = " + w.add(rt2));
System.out.println("w - rt2 = " + w.subtract(rt2));
System.out.println("w * rt2 = " + w.multiply(rt2));
System.out.println("w / rt2 = " + w.divide(rt2));
}
/* Here's the output:
iris 201% java visad.RealTuple
rt1 = (1, 2, 3)
rt2 = (6, 5, 4)
rt1 + rt2 = (7, 7, 7)
rt1 - rt2 = (-5, -3, -1)
rt1 * rt2 = (6, 10, 12)
rt1 / rt2 = (0.166667, 0.4, 0.75)
sqrt(rt1) = (1, 1.41421, 1.73205)
rt1 + w = (11, 12, 13)
rt1 - w = (-9, -8, -7)
rt1 * w = (10, 20, 30)
rt1 / w = (0.1, 0.2, 0.3)
w + rt2 = (16, 15, 14)
w - rt2 = (4, 5, 6)
w * rt2 = (60, 50, 40)
w / rt2 = (1.66667, 2, 2.5)
iris 202%
*/
}