//
// 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;
    }
     */

}


 

Ads help maintain this website.