// // CachedFlatField // /* * 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, Jeff McWhirter. * * 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.data; import visad.*; import visad.util.DataUtility; import java.rmi.RemoteException; /** * This is a FloatField that caches to disk its float array. */ public class CachedFlatField extends FlatField { /** the id for this instance */ private Object cacheId; private boolean inCache = false; /** Mutex */ transient protected Object MUTEX = new Object(); /** The min/max ranges */ DataRange[] ranges; /** The min/max ranges */ DataRange[] sampleRanges; private CachedFlatField parent; /** * Create a new CachedFlatField * * @param type Function type * @param domainSet set for this * * @throws VisADException On badness */ public CachedFlatField(FunctionType type, Set domainSet) throws VisADException { this(type, domainSet, (CoordinateSystem) null, (Set[]) null, (Unit[]) null, null); } /** * Create a new CachedFlatField * * @param floats The values * @param type Function type * * @throws VisADException On badness */ public CachedFlatField(FunctionType type, float[][] floats) throws VisADException { this(type, type.getDomain().getDefaultSet(), (CoordinateSystem) null, (Set[]) null, (Unit[]) null, floats); } /** * Create a new CachedFlatField * * @param floats The values * @param type Function type * @param domainSet Domain * * @throws VisADException On badness */ public CachedFlatField(FunctionType type, Set domainSet, float[][] floats) throws VisADException { this(type, domainSet, (CoordinateSystem) null, (Set[]) null, (Unit[]) null, floats); } /** * Create a new CachedFlatField * * @param type Function type * @param domainSet Domain * @param rangeCoordSys range CoordSystem * @param rangeSets range sets * @param units units * @param floats The values * * @throws VisADException On badness */ public CachedFlatField(FunctionType type, Set domainSet, CoordinateSystem rangeCoordSys, Set[] rangeSets, Unit[] units, float[][] floats) throws VisADException { this(type, domainSet, rangeCoordSys, null, rangeSets, units, floats); } /** * Create a new CachedFlatField * * @param type Function type * @param domainSet Domain * @param rangeCoordSys range CoordSystem * @param rangeCoordSyses range CoordSystem's * @param rangeSets range sets * @param units units * @param floats The values * * @throws VisADException On badness */ public CachedFlatField(FunctionType type, Set domainSet, CoordinateSystem rangeCoordSys, CoordinateSystem[] rangeCoordSyses, Set[] rangeSets, Unit[] units, float[][] floats) throws VisADException { super(type, domainSet, rangeCoordSys, null, rangeSets, units); initCache(floats); } /** * Copy constructor * * @param that What we clone from * @param copy copy the values * @param type Function type * @param domainSet Domain * @param rangeCoordSys range CoordSystem * @param rangeCoordSysArray rangeCoordSysArray * @param rangeSets range sets * @param units units * * @throws VisADException On badness */ public CachedFlatField(CachedFlatField that, boolean copy, FunctionType type, Set domainSet, CoordinateSystem rangeCoordSys, CoordinateSystem[] rangeCoordSysArray, Set[] rangeSets, Unit[] units) throws VisADException { super(type, domainSet, rangeCoordSys, rangeCoordSysArray, rangeSets, units); this.ranges = that.ranges; this.sampleRanges = that.sampleRanges; this.cacheId = null; this.inCache = false; //Get the values from the cloned field if they had read their values if(that.haveData()) { // msg("CCF - cloned object is in cache"); // We used to ignore the copy flag - if this causes problems, // change back to true //float[][] values = that.unpackFloats(true); float[][] values = that.unpackFloats(copy); if(values == null) { parent = that; } initCache(values); } else { this.parent = that; clearMissing(); // msg("CCF - cloned object not in cache"); } } /** * Clone this object * * @param copy copy the values * @param type Function type * @param domainSet Domain set * @param rangeCoordSys range CoordSystem * @param rangeCoordSysArray rangeCoordSysArray * @param rangeSets range sets * @param units units * * @return New field * * @throws VisADException On badness */ public CachedFlatField cloneMe(boolean copy, FunctionType type, Set domainSet, CoordinateSystem rangeCoordSys, CoordinateSystem[] rangeCoordSysArray, Set[] rangeSets, Unit[] units) throws VisADException { CachedFlatField ccf = new CachedFlatField(this, copy, type, domainSet, rangeCoordSys, rangeCoordSysArray, rangeSets, units); return ccf; } public void finalize() throws Throwable { super.finalize(); // System.err.println("CachedFlatField.finalize"); if(cacheId!=null) { DataCacheManager.getCacheManager().removeFromCache(cacheId); } } /** * Set the sample * * @param values the samples * @param errors errors * @param copy tru to copy * * @throws RemoteException Java RMI Exception * @throws VisADException Problem in VisAD land */ public void setSamples(float[][] values, ErrorEstimate[] errors, boolean copy) throws VisADException, RemoteException { float[][]myFloatValues = new float[values.length][]; for (int i = 0; i < myFloatValues.length; i++) { if (copy) { myFloatValues[i] = (float[]) values[i].clone(); } else { myFloatValues[i] = values[i]; } } setRangeErrors(errors); this.getRanges(values); if(inCache) { DataCacheManager.getCacheManager().updateData(cacheId, myFloatValues); } else { initCache(myFloatValues); } } static int cnt = 0; public final int mycnt = cnt++; /** * Override method so we clear the caches on the cloned object * * @return the clone */ public Object clone() { try { // msg("CCF.clone"); CachedFlatField ccf = (CachedFlatField) super.clone(); ccf.cacheId = null; float[][]newValues = ccf.unpackFloats(false); ccf.nullRanges(); ccf.initCache(newValues); return ccf; } catch(Exception exc) { exc.printStackTrace(); throw new RuntimeException(exc); } } /** * init * * @param data data * * @throws VisADException initializing field */ protected void initCache(float[][] data) throws VisADException { if(data!=null) { if(cacheId!=null) { DataCacheManager.getCacheManager().updateData(cacheId, data); } else { cacheId = DataCacheManager.getCacheManager().addToCache(getClass().getSimpleName(), data); } inCache = true; } //Read the ranges when we first have data if (ranges == null) { getRanges(data); } clearMissing(); } /** * Set the sample ranges * * @param sampleRanges the sample ranges */ public void setSampleRanges(DataRange[] sampleRanges) { this.sampleRanges = sampleRanges; } /** * Clear the cached ranges */ public void clearCachedRange() { sampleRanges = null; ranges = null; } /** * Get the ranges * * @return ranges * * @throws VisADException problem getting ranges */ public DataRange[] getRanges() throws VisADException { return getRanges(false); } /** * Get the ranges * * * @param force force a recalc * @return ranges the ranges * * @throws VisADException problem getting ranges */ public DataRange[] getRanges(boolean force) throws VisADException { if (force) { sampleRanges = null; } if (ranges != null) { return ranges; } if (sampleRanges != null) { return sampleRanges; } // msg("making ranges"); return getRanges(unpackFloats(false)); } /** * Get the ranges for the values * * @param values the values * * @return the ranges * * @throws VisADException Problem in VisAD land */ public DataRange[] getRanges(float[][] values) throws VisADException { sampleRanges = null; if (values == null) { return null; } ranges = new DataRange[values.length]; for (int rangeIdx = 0; rangeIdx < values.length; rangeIdx++) { float pMin = Float.POSITIVE_INFINITY; float pMax = Float.NEGATIVE_INFINITY; float[] values_range = values[rangeIdx]; int length = values_range.length; for (int i = 0; i < length; i++) { float value = values_range[i]; if (pMax < value) { pMax = value; } if (pMin > value) { pMin = value; } } ranges[rangeIdx] = new DataRange(pMin, pMax); } // msg("done making ranges"); return ranges; } /** * Used to provide a hook to derived classes to dynamically read in the data * * @return data */ public float[][] readData() { // msg(" CachedFlatField.readData"); return null; } /** * Debug statment * * @param s message to print */ public void msg(String s) { // System.err.println("ccf:"+ mycnt + ": " + s); } /** * Read data from cache * * @return the values from the cache * * @throws VisADException problem reading data */ private float[][] getMyValues() throws VisADException { // msg("CCF - getMyValues " + inCache); if(inCache) { if(cacheId == null) { // msg("CCF - WHoa, inCache=true but no cacheId"); return null; } return DataCacheManager.getCacheManager().getFloatArray2D(cacheId); } float[][] values = null; //If we don't have the values and we have a ccf that we were cloned from //then read the data from it and clear it out if(parent!=null) { values = parent.unpackFloats(true); readValuesFromParent(parent); parent = null; } if (values == null) { values = readData(); } if (values == null) { // msg("Floats still null after readData"); return null; } initCache(values); return values; } public boolean haveData() { return inCache; } /** * This gets called to notify derived classes that we jus got the data from the parent ccf * * @param parent The parent CCF we read data from */ protected void readValuesFromParent(CachedFlatField parent) throws VisADException { } /** * Get the range value at the index-th sample. * * @param index index of the sample * @return Data object (Real, RealTuple, or Tuple) corresponding to * the range at the index-th sample. * @throws VisADException problem getting data * @throws RemoteException problem getting data from remote object */ public Data getSample(int index) throws VisADException, RemoteException { // msg("getSample"); float[][] values = getMyValues(); if (values == null) { // msg("Floats still null"); return null; } MathType Type = getType(); ErrorEstimate[] RangeErrors = getRangeErrors(); if (isMissing() || (index < 0) || (index >= getLength())) { // msg("is missing"); return ((FunctionType) Type).getRange().missingData(); } double[][] range = new double[TupleDimension][1]; for (int i = 0; i < TupleDimension; i++) { range[i][0] = (double) values[i][index]; } MathType RangeType = ((FunctionType) Type).getRange(); if (RangeType instanceof RealType) { return new Real((RealType) RangeType, range[0][0], RangeUnits[0], RangeErrors[0]); } else if (RangeType instanceof RealTupleType) { Real[] reals = new Real[TupleDimension]; for (int j = 0; j < TupleDimension; j++) { MathType type = ((RealTupleType) RangeType).getComponent(j); reals[j] = new Real((RealType) type, range[j][0], RangeUnits[j], RangeErrors[j]); } return new RealTuple((RealTupleType) RangeType, reals, RangeCoordinateSystem); } else { // RangeType is a Flat TupleType int n = ((TupleType) RangeType).getDimension(); int j = 0; Data[] datums = new Data[n]; for (int i = 0; i < n; i++) { MathType type = ((TupleType) RangeType).getComponent(i); if (type instanceof RealType) { datums[i] = new Real((RealType) type, range[j][0], RangeUnits[j], RangeErrors[j]); j++; } else { // type instanceof RealTupleType int m = ((RealTupleType) type).getDimension(); Real[] reals = new Real[m]; for (int k = 0; k < m; k++) { RealType ctype = (RealType) ((RealTupleType) type).getComponent(k); reals[k] = new Real(ctype, range[j][0], RangeUnits[j], RangeErrors[j]); j++; } datums[i] = new RealTuple((RealTupleType) type, reals, RangeCoordinateSystems[i]); } } return new Tuple(datums, false); } } /** * get the float values as doubles * * @param copy copy the values * * @return The values * * @throws VisADException On badness */ protected double[][] unpackValues(boolean copy) throws VisADException { float[][] values = unpackFloats(false); if (values == null) { msg ("unpackValues: ccf: values are null "); return null; } double[][] doubles = new double[values.length][]; for (int i = 0; i < values.length; i++) { float[] values_i = values[i]; double[] doubles_i = new double[values_i.length]; doubles[i] = doubles_i; for (int j = 0; j < values_i.length; j++) { doubles_i[j] = values_i[j]; } } return doubles; } /** * get the float values * * @param copy copy the values * * @return The values * * @throws VisADException On badness */ public float[][] unpackFloats(boolean copy) throws VisADException { // msg("unpackFloats copy=" + copy); float[][] values = getMyValues(); if (values == null) { // msg("unpackFloats gives null"); // System.err.println(mycnt+" CCF.unpackFloats - values are still null"); return super.unpackFloats(copy); } float[][] result = null; result = new float[values.length][]; for (int i = 0; i < result.length; i++) { if (copy) { result[i] = (float[]) values[i].clone(); } else { result[i] = values[i]; } } return result; } /** * Unpack floats * * @param s_index the sample index * * @return the floats for that index * * @throws VisADException Problem in VisAD land */ protected float[] unpackFloats(int s_index) throws VisADException { float[][] values = getMyValues(); if (values == null) { return null; } float[] range = new float[values.length]; for (int i = 0; i < TupleDimension; i++) { range[i] = values[i][s_index]; } return range; } /** * Make a clone of this using the new type, units and errors. Called * from unary and binar * * @param f_type the new FunctionType * @param units the new Units * @param errors the new Errors * @param newValues the new values * * @return a new FlatField * * @throws VisADException Problem in VisAD land protected FlatField cloneFloat(MathType f_type, Unit[] units, ErrorEstimate[] errors, float[][] newValues) throws VisADException { MathType N_type = ((f_type == null) ? getType() : f_type); // create (initially missing) FlatField for return // use FloatSet rather than RangeSet for intermediate computation results Set[] sets = new Set[TupleDimension]; for (int i = 0; i < TupleDimension; i++) { SetType set_type = new SetType( ((FunctionType) N_type).getFlatRange().getComponent(i)); sets[i] = new FloatSet(set_type); } RealTupleType d_type = ((FunctionType) N_type).getDomain(); Set new_set = null; if ( !d_type.equals(((FunctionType) getType()).getDomain())) { new_set = (Set) getDomainSet().cloneButType(d_type); } else { new_set = getDomainSet(); } if (newValues == null) { //If we don't have the values array then copy this one. newValues = unpackFloats(true); } CachedFlatField field = new CachedFlatField((FunctionType) N_type, new_set, RangeCoordinateSystem, RangeCoordinateSystems, sets, units, newValues); return field; } */ }