//
// Gridded1DDoubleSet.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.lang.ref.WeakReference;
import java.util.WeakHashMap;
/**
Gridded1DDoubleSet is a Gridded1DSet with double-precision samples.
*/
public class Gridded1DDoubleSet extends Gridded1DSet
implements GriddedDoubleSet {
double[] Low = new double[1];
double[] Hi = new double[1];
double LowX, HiX;
double[][] Samples;
/**
* A canonicalizing cache of previously-created instances. Because instances
* are immutable, a cache can be used to reduce memory usage by ensuring
* that each instance is truly unique. By implementing the cache using a
* {@link WeakHashMap}, this can be accomplished without the technique itself
* adversely affecting memory usage.
*/
private static final WeakHashMap cache = new WeakHashMap();
// Overridden Gridded1DSet constructors (float[][])
/** a 1-D sequence with no regular interval with null errors,
CoordinateSystem and Units are defaults from type */
public Gridded1DDoubleSet(MathType type, float[][] samples, int lengthX)
throws VisADException {
this(type, Set.floatToDouble(samples), lengthX, null, null, null, true);
}
public Gridded1DDoubleSet(MathType type, float[][] samples, int lengthX,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors) throws VisADException {
this(type, Set.floatToDouble(samples), lengthX,
coord_sys, units, errors, true);
}
/** a 1-D sorted sequence with no regular interval. samples array
is organized float[1][number_of_samples] where lengthX =
number_of_samples. samples must be sorted (either increasing
or decreasing). coordinate_system and units must be compatible
with defaults for type, or may be null. errors may be null */
public Gridded1DDoubleSet(MathType type, float[][] samples, int lengthX,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors, boolean copy)
throws VisADException {
this(type, Set.floatToDouble(samples), lengthX,
coord_sys, units, errors, copy);
}
// Corresponding Gridded1DDoubleSet constructors (double[][])
/** a 1-D sequence with no regular interval with null errors,
CoordinateSystem and Units are defaults from type */
public Gridded1DDoubleSet(MathType type, double[][] samples, int lengthX)
throws VisADException {
this(type, samples, lengthX, null, null, null, true);
}
public Gridded1DDoubleSet(MathType type, double[][] samples, int lengthX,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors) throws VisADException {
this(type, samples, lengthX, coord_sys, units, errors, true);
}
/** a 1-D sorted sequence with no regular interval. samples array
is organized double[1][number_of_samples] where lengthX =
number_of_samples. samples must be sorted (either increasing
or decreasing). coordinate_system and units must be compatible
with defaults for type, or may be null. errors may be null */
public Gridded1DDoubleSet(MathType type, double[][] samples, int lengthX,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors, boolean copy)
throws VisADException {
super(type, null, lengthX, coord_sys, units, errors, copy);
if (samples == null) {
throw new SetException("Gridded1DDoubleSet: samples are null");
}
init_doubles(samples, copy);
LowX = Low[0];
HiX = Hi[0];
LengthX = Lengths[0];
if (Samples != null && Lengths[0] > 1) {
// samples consistency test
for (int i=0; i Samples[0][0]);
if (Ascending) {
for (int i=1; i Samples[0][i-1]) {
throw new SetException(
"Gridded1DDoubleSet: samples do not form a valid grid ("+i+")");
}
}
}
}
}
/**
* Returns an instance of this class. This method uses a weak cache of
* previously-created instances to reduce memory usage.
*
* @param type The type of the set. Must be a {@link
* RealType} or a single-component {@link
* RealTupleType} or {@link SetType}.
* @param samples The values in the set.
* samples[i] is the value of
* the ith sample point. Must be sorted (either
* increasing or decreasing). May be
* null. The array is not copied, so
* either don't modify it or clone it first.
* @param coordSys The coordinate system for this, particular, set.
* Must be compatible with the default coordinate
* system. May be null.
* @param unit The unit for the samples. Must be compatible
* with the default unit. May be
* null.
* @param error The error estimate of the samples. May be
* null.
*/
public static synchronized Gridded1DDoubleSet create(
MathType type,
double[] samples,
CoordinateSystem coordSys,
Unit unit,
ErrorEstimate error)
throws VisADException
{
Gridded1DDoubleSet newSet =
new Gridded1DDoubleSet(
type, new double[][] {samples}, samples.length, coordSys,
new Unit[] {unit}, new ErrorEstimate[] {error}, false);
WeakReference ref = (WeakReference)cache.get(newSet);
if (ref == null)
{
/*
* The new instance is unique (any and all previously-created identical
* instances no longer exist).
*
* A WeakReference is used in the following because values of a
* WeakHashMap aren't "weak" themselves and must not strongly reference
* their associated keys either directly or indirectly.
*/
cache.put(newSet, new WeakReference(newSet));
}
else
{
/*
* The new instance is a duplicate of a previously-created one.
*/
Gridded1DDoubleSet oldSet = (Gridded1DDoubleSet)ref.get();
if (oldSet == null)
{
/* The previous instance no longer exists. Save the new instance. */
cache.put(newSet, new WeakReference(newSet));
}
else
{
/* The previous instance still exists. Reuse it to save memory. */
newSet = oldSet;
}
}
return newSet;
}
// Overridden Gridded1DSet methods (float[][])
public float[][] getSamples() throws VisADException {
return getSamples(true);
}
public float[][] getSamples(boolean copy) throws VisADException {
return Set.doubleToFloat(Samples);
}
/** convert an array of 1-D indices to an array of values in
R^DomainDimension */
public float[][] indexToValue(int[] index) throws VisADException {
return Set.doubleToFloat(indexToDouble(index));
}
/**
* Convert an array of values in R^DomainDimension to an array of
* 1-D indices. This Gridded1DDoubleSet must have at least two points in the
* set.
* @param value An array of coordinates. value[i][j]
* contains the ith component of the
* jth point.
* @return Indices of nearest points. RETURN_VALUE[i]
* will contain the index of the point in the set closest
* to value[][i] or -1 if
* value[][i] lies outside the set.
*/
public int[] valueToIndex(float[][] value) throws VisADException {
return doubleToIndex(Set.floatToDouble(value));
}
public float[][] gridToValue(float[][] grid) throws VisADException {
return Set.doubleToFloat(gridToDouble(Set.floatToDouble(grid)));
}
/** transform an array of values in R^DomainDimension to an array
of non-integer grid coordinates */
public float[][] valueToGrid(float[][] value) throws VisADException {
return Set.doubleToFloat(doubleToGrid(Set.floatToDouble(value)));
}
/** for each of an array of values in R^DomainDimension, compute an array
of 1-D indices and an array of weights, to be used for interpolation;
indices[i] and weights[i] are null if i-th value is outside grid
(i.e., if no interpolation is possible) */
public void valueToInterp(float[][] value, int[][] indices,
float[][] weights) throws VisADException
{
int len = weights.length;
double[][] w = new double[len][];
doubleToInterp(Set.floatToDouble(value), indices, w);
for (int i=0; i 1");
}
*/
int length = grid[0].length;
double[][] value = new double[1][length];
for (int i=0; i LengthX-0.5) ) {
value[0][i] = Double.NaN;
} else if (Length == 1) {
value[0][i] = Samples[0][0];
} else {
// calculate closest integer variable
int ig;
if (g < 0) ig = 0;
else if (g >= LengthX-1) ig = LengthX - 2;
else ig = (int) g;
double A = g - ig; // distance variable
// do the linear interpolation
value[0][i] = (1-A)*Samples[0][ig] + A*Samples[0][ig+1];
}
}
return value;
}
// WLH 6 Dec 2001
//private int ig = -1;
/** transform an array of values in R^DomainDimension to an array
of non-integer grid coordinates */
public double[][] doubleToGrid(double[][] value) throws VisADException {
if (value.length < DomainDimension) {
throw new SetException("Gridded1DDoubleSet.doubleToGrid: value dimension " +
value.length + " not equal to Domain dimension " +
DomainDimension);
}
/*
if (Lengths[0] < 2) {
throw new SetException("Gridded1DDoubleSet.doubleToGrid: " +
"requires all grid dimensions to be > 1");
}
*/
double[] vals = value[0];
int length = vals.length;
double[] samps = Samples[0];
double[][] grid = new double[1][length];
int ig = (LengthX - 1)/2;
/* WLH 6 Dec 2001
// use value from last call as first guess, if reasonable
if (ig < 0 || ig >= LengthX) {
ig = (LengthX - 1)/2;
}
*/
for (int i=0; i vals[i]) {
lower = ig+1;
}
else if (Ascending ? samps[ig] > vals[i] : samps[ig] < vals[i]) {
upper = ig;
}
if (lower < upper) ig = (lower + upper) / 2;
}
// Newton's method
double solv = ig + (vals[i] - samps[ig]) / (samps[ig+1] - samps[ig]);
if (solv > -0.5 && solv < LengthX - 0.5) grid[0][i] = solv;
else {
grid[0][i] = Double.NaN;
// next guess should be in the middle if previous value was missing
ig = (LengthX - 1)/2;
}
}
}
return grid;
}
/** for each of an array of values in R^DomainDimension, compute an array
of 1-D indices and an array of weights, to be used for interpolation;
indices[i] and weights[i] are null if i-th value is outside grid
(i.e., if no interpolation is possible) */
public void doubleToInterp(double[][] value, int[][] indices,
double[][] weights) throws VisADException
{
if (value.length != DomainDimension) {
throw new SetException("Gridded1DDoubleSet.doubleToInterp: value dimension " +
value.length + " not equal to Domain dimension " +
DomainDimension);
}
int length = value[0].length; // number of values
if (indices.length != length) {
throw new SetException("Gridded1DDoubleSet.doubleToInterp: indices length " +
indices.length +
" doesn't match value[0] length " +
value[0].length);
}
if (weights.length != length) {
throw new SetException("Gridded1DDoubleSet.doubleToInterp: weights length " +
weights.length +
" doesn't match value[0] length " +
value[0].length);
}
// convert value array to grid coord array
double[][] grid = doubleToGrid(value);
int i, j, k; // loop indices
int lis; // temporary length of is & cs
int length_is; // final length of is & cs, varies by i
int isoff; // offset along one grid dimension
double a, b; // weights along one grid dimension; a + b = 1.0
int[] is; // array of indices, becomes part of indices
double[] cs; // array of coefficients, become part of weights
int base; // base index, as would be returned by valueToIndex
int[] l = new int[ManifoldDimension]; // integer 'factors' of base
// fractions with l; -0.5 <= c <= 0.5
double[] c = new double[ManifoldDimension];
// array of index offsets by grid dimension
int[] off = new int[ManifoldDimension];
off[0] = 1;
for (j=1; j= 0.0))) {
// only interp along ManifoldDimension-1
// if between two valid grid coords
length_is *= 2;
}
base = l[ManifoldDimension-1];
}
for (j=ManifoldDimension-2; j>=0 && base>=0; j--) {
if (Double.isNaN(grid[j][i])) {
base = -1;
}
else {
l[j] = (int) (grid[j][i] + 0.5);
if (l[j] == Lengths[j]) l[j]--; // WLH 23 Dec 99
c[j] = grid[j][i] - ((double) l[j]);
if (!((l[j] == 0 && c[j] <= 0.0) ||
(l[j] == Lengths[j] - 1 && c[j] >= 0.0))) {
// only interp along dimension j if between two valid grid coords
length_is *= 2;
}
base = l[j] + Lengths[j] * base;
}
}
if (base < 0) {
// value is out of grid so return null
is = null;
cs = null;
}
else {
// create is & cs of proper length, and init first element
is = new int[length_is];
cs = new double[length_is];
is[0] = base;
cs[0] = 1.0f;
lis = 1;
for (j=0; j= 0.0))) {
// only interp along dimension j if between two valid grid coords
if (c[j] >= 0.0) {
// grid coord above base
isoff = off[j];
a = 1.0f - c[j];
b = c[j];
}
else {
// grid coord below base
isoff = -off[j];
a = 1.0f + c[j];
b = -c[j];
}
// double is & cs; adjust new offsets; split weights
for (k=0; k Hi[j]) Hi[j] = SamplesJ[i];
}
else {
SamplesJ[i] = Double.NaN;
}
sum += SamplesJ[i];
}
if (SetErrors[j] != null ) {
SetErrors[j] =
new ErrorEstimate(SetErrors[j].getErrorValue(), sum / Length,
Length, SetErrors[j].getUnit());
}
super.Low[j] = (float) Low[j];
super.Hi[j] = (float) Hi[j];
}
}
public void cram_missing(boolean[] range_select) {
int n = Math.min(range_select.length, Samples[0].length);
for (int i=0; i
Ads help maintain this website.