//
// 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.