Package simtools.data.merge

Source Code of simtools.data.merge.SynchronousMergeDSCollection$MergedCollectionContainer

/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2006, by :
*     Corporate:
*         EADS Astrium SAS
*         EADS CRC
*     Individual:
*         Claude Cazenave
*
* $Id: SynchronousMergeDSCollection.java,v 1.8 2008/04/08 11:53:42 ogor Exp $
*
* Changes
* -------
* 20 janv. 2006 : Initial public release (CC);
*
*/
package simtools.data.merge;

import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import simtools.data.CollectiveDataSource;
import simtools.data.DataException;
import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourceCollection;
import simtools.data.DataSourcePool;
import simtools.data.DuplicateIdException;
import simtools.data.NoSuchIndex;
import simtools.data.UnsupportedOperation;
import simtools.data.async.TimeStampedDataSource;
import simtools.data.async.TimeStampedDataSourceCollection;

/**
*
* <p>Synchronize data sources according to a frequency and a time range.
* This class provides a 0 and and 1-order interpolation of data
* </p>
* Following steps have to be performed to synchronize data together:
* <ol>
<li>Create a SynchronousMergeDSCollection
<li>Add data using MergeDSCollection methods
<li>Call mergeData method to allocate and initialize data buffers
* </ol>
*
*
* @author zxpletran007
*
*/
public class SynchronousMergeDSCollection extends DataSourceCollection implements MergeDSCollection{

    static Logger _logger = simtools.util.LogConfigurator.getLogger(SynchronousMergeDSCollection.class.getName());
    public static final String ID_MARKER="SynchronousMergeDSCollection:";


    // If a TM repository has more than hugeRepertorySize data sources, it can be structured in an sub arborescence.
    // Thus sub repositories are created with the different first letters of thoses data sources.
    protected final static int HUGEREPERTORYSIZE = 10;
    protected MergedCollectionContainer collectionRoot;
    protected String collectionName;

    protected DoubleBuffer mergedTimeBuffer;
    protected DataSource mergedTimeDs;

    /** The first merged time value */
    protected double mergedTimeStart;

    /**  The number of merged time values */
    protected long mergedTimeLength;

    /** Merged time frequency */
    protected double mergedTimeFreq;

    /** If true mergedTime is a number of seconds, otherwise this is a number of milliseconds since 01/01/1970 00:00:00:*/
    protected boolean timeRefIsRelative; 

    /** Interpolation order can be 0 or 1 */
    protected int interpolationOrder; 
   
    public SynchronousMergeDSCollection(
            String collectionName,
            int interpolationOrder,
            boolean timeRefIsRelative,
            DataSource mergedTimeReferenceDs,
            boolean mergedTimeReferenceDsIsRelative,
            double mergedTimeReferenceDsOffset,
            double mergedTimeReferenceDsInitData
    ) throws MergeDataException {
        super();
        this.collectionName = collectionName;
        this.timeRefIsRelative = timeRefIsRelative;

        if ((interpolationOrder != 0) && (interpolationOrder != 1)){
            throw new MergeDataException("Interpolation ordrer shall be equal to 0 or 1");
        }
        this.interpolationOrder = interpolationOrder;
        this.mergedTimeLength = -1;

        collectionRoot = new MergedCollectionContainer("");
        map = new HashMap();

        // Compute mergedTimeFreq using mergedTimeReferenceDs.
        if (mergedTimeReferenceDs == null){
            throw new MergeDataException("Merged Time Reference Ds is missing");
        }

        if (mergedTimeReferenceDs.sortedOrder() != 1) {
            throw new MergeDataException("The reference for merged time: " + DataInfo.getId(mergedTimeReferenceDs) + "  is not sorted");
        }
        computeMergedTimeFrequency(mergedTimeReferenceDs, mergedTimeReferenceDsIsRelative, mergedTimeReferenceDsOffset, mergedTimeReferenceDsInitData);

        // Create collection time data source
        mergedTimeDs = new TimeSource();
        add(mergedTimeDs);
        map.put(DataInfo.getId(mergedTimeDs),mergedTimeDs);
        addToCollectionArborescence(DataInfo.getId(mergedTimeDs), mergedTimeDs);
    }


    /**
     * Compute a time value for specified index.
     * @param timeDs
     * @param index
     * @param isRelative
     * @param offset
     * @param initialDate
     * @return the related time value
     * @throws DataException
     */
    private double getTimeValue(DataSource timeDs, long index, boolean isRelative, double offset, double initialDate)throws MergeDataException{
        double timevalue =0;
        try{
            timevalue = timeDs.getDoubleValue(index);
        } catch (DataException e){
            throw new MergeDataException(e.getMessage());
        }

        if (isRelative && timeRefIsRelative){
            timevalue+=offset;

        }else if (!isRelative && !timeRefIsRelative){
            timevalue+=offset*1000;

        }else if (!isRelative && timeRefIsRelative){
            // (ti-t0)/1000 + offset
            timevalue= (timevalue-initialDate)/1000.0 + offset;

        }else if (isRelative && !timeRefIsRelative){
            // initialDate + ti*1000 + offset*1000
            timevalue= initialDate + timevalue*1000.0 + offset*1000.0;
        }
        return timevalue;
    }


    /** We do accept this drift when checking a data source period */
    public static final double MAX_T_DRIFT=1e-1;

    /**
     * Compute merged time frequency
     * @param timeDs
     * @param isRelative
     * @param offset
     * @param initialDate
     * @throws DataException
     */
    protected void computeMergedTimeFrequency(DataSource timeDs,  boolean isRelative, double offset, double initialDate) throws MergeDataException{
        try {
            mergedTimeFreq = -1;
            mergedTimeStart = getTimeValue(timeDs, timeDs.getStartIndex(), isRelative, offset, initialDate);

            long j0 = timeDs.getStartIndex();
            long j = j0 + 1;

            while(j <= timeDs.getLastIndex()) {
                double t = getTimeValue(timeDs, j, isRelative, offset, initialDate);
                if((j-j0)==1){
                    mergedTimeFreq = t - mergedTimeStart;
                    if(mergedTimeFreq <= 0.){
                        j--;
                        break;
                    }
                }
                else{
                    if(Math.abs(t -(mergedTimeStart + mergedTimeFreq*(j-j0))) > MAX_T_DRIFT){
                        throw new MergeDataException("Data source reference for dating merged elements is not periodical");
                    }
                }
                j++;
            }

            if(mergedTimeFreq <= 0.) {
                throw new MergeDataException("Invalid merged time frequency = " + mergedTimeLength);
            }

            mergedTimeLength = timeDs.getLastIndex() - timeDs.getStartIndex() +1;

            startIndex =  0;
            lastIndex = mergedTimeLength -1 ;

            _logger.fine("Following frequency is used for merged time: " + mergedTimeFreq);

        } catch (DataException e) {
            throw new MergeDataException(e.getMessage());
        }
    }

   
    /**
     * Update merged time bounds
     * @param timeDs
     * @param isRelative
     * @param offset
     * @param initialDate
     * @throws DataException
     */
    protected void updateMergedTimeBounds(DataSource timeDs, boolean isRelative,double offset,double initialDate) throws MergeDataException{
        try{
            double startTime = getTimeValue(timeDs, timeDs.getStartIndex(), isRelative, offset, initialDate);
            double endTime = getTimeValue(timeDs, timeDs.getLastIndex(), isRelative, offset, initialDate);

            double mergedTimeEnd = mergedTimeStart + (mergedTimeLength-1) * mergedTimeFreq;

            if ( ((startTime < mergedTimeStart&&  (endTime <= mergedTimeStart)) ||  (startTime >= mergedTimeEnd) ){ 
                // Intersection is empty
                throw new MergeDataException("This interval [" + startTime + " ; " + endTime + "] " +
                        "does not match with current merged time: [" + mergedTimeStart + " ; " + mergedTimeEnd + "]" );
            }
            boolean hasChanged = false;

            if (startTime > mergedTimeStart){
                mergedTimeStart = startTime;
                hasChanged = true;
            }
            if (endTime < mergedTimeEnd){
                // Compute the new mergedTimeLength
                mergedTimeEnd = mergedTimeStart;
                mergedTimeLength= 1;

                while( (mergedTimeEnd + mergedTimeFreq) <= endTime){
                    mergedTimeEnd += mergedTimeFreq;
                    mergedTimeLength++;
                }
                hasChanged = true;
            }
            if (hasChanged){
                // update last Index
                lastIndex = mergedTimeLength -1 ;

                _logger.fine("updateTime : begin time = " + mergedTimeStart + " length  = " +  mergedTimeLength + "endTime : begin time = " + mergedTimeEnd );
            }
           
        }catch (DataException e){
            throw new MergeDataException(e.getMessage());
        }
    }
   
   
   

   
    /**
     * @param dataList
     * @throws MergeDataException
     */
    public void add(List dataList) throws MergeDataException{
        for(int i=0;i<dataList.size(); i++){
           
        }
    }
    /* (non-Javadoc)
     * @see simtools.data.merge.MergeDSCollection#add(simtools.data.async.TimeStampedDataSourceCollection)
     */
    public void add(TimeStampedDataSourceCollection tsdsc, double offset, double initialDate) throws MergeDataException{

        // Disable invalid operations
        if( (tsdsc instanceof MergeDSCollection) ){
            throw new IllegalArgumentException(DataInfo.getId(tsdsc) + " is already a merge of collection");
        }
        DataSource addedDs = null;

        for(int i=0;i<tsdsc.size();i++) {
            try {
                if ( ! (tsdsc.get(i) instanceof TimeStampedDataSource)){
                    continue;
                }

                TimeStampedDataSource ds = (TimeStampedDataSource)tsdsc.get(i);
                String id =DataInfo.getId(ds);

                if (get(id)!=null){
                    id +=  "_" + DataInfo.getLabel(tsdsc)//  If data source name already exists then add collection name as a suffix
                }
                if (get(id)==null){
                    // 1 - Update merged time
                    if (ds.getTime().sortedOrder() != 1) {
                        throw new MergeDataException("Cannot add " + DataInfo.getId(ds) + " because its time reference is not sorted");
                    }
                    updateMergedTimeBounds(ds.getTime(), false, offset, initialDate);

                    // 2- Create data source
                    addedDs = new DirectSynchronousMergedDataSource(id, this,size(), ds, ds.getTime(), false, offset, initialDate);

                    // 3 - Add data source to collection
                    addToCollectionArborescence(DataInfo.getId(addedDs), addedDs);
                    add(addedDs);
                    map.put(id, addedDs);
                }
            } catch (MergeDataException e){
            }
        }
        sortHugeRepertories();
    }




    /* (non-Javadoc)
     * @see simtools.data.merge.MergeDSCollection#add(simtools.data.DataSourceCollection, simtools.data.DataSource, double)
     */
    public void add(DataSourceCollection dsc, DataSource timeDs, boolean isRelative, double offset, double initialDate) throws  MergeDataException{
        if ( (dsc==null) || (timeDs==null))
            throw new MergeDataException("Null argument when merging data");

        // disable invalid operations
        if(dsc instanceof MergeDSCollection){
            throw new MergeDataException(DataInfo.getId(dsc) + " is already a merge of collection");
       

        DataSource addedDs=null;

        // 1 - Update merged time
        if (timeDs.sortedOrder() != 1) {
            throw new MergeDataException("Cannot add " + DataInfo.getId(dsc) + " because its time reference is not sorted");
        }
        updateMergedTimeBounds(timeDs, isRelative, offset, initialDate);

        for(int i=0;i<dsc.size();i++){
            CollectiveDataSource data =(CollectiveDataSource)dsc.get(i);
            String id  = DataInfo.getId(data);

            if (!(id.equals(DataInfo.getId(timeDs)))){  //  Do not add the time reference to merge collection
                if (get(id)!=null){
                    id += "_" + dsc.getInformation().label; // if data source name already exists then add collection name as a suffix
                }
                if (get(id)==null) {  

                    // 2- Create data source
                    addedDs = new DirectSynchronousMergedDataSource(id, this,size(), data, timeDs, isRelative, offset, initialDate);

                    // 3 - Add data source to collection
                    addToCollectionArborescence(DataInfo.getId(addedDs), addedDs);
                    add(addedDs);
                    map.put(id, addedDs);
                }
            }
        }
        sortHugeRepertories();
    }


    /* (non-Javadoc)
     * @see simtools.data.merge.MergeDSCollection#add(simtools.data.DataSource, simtools.data.DataSource, double)
     */
    public void add(DataSource ds, DataSource timeDs, boolean isRelative, double offset,  double initialDate) throws MergeDataException{
        if ( (ds==null) || (timeDs==null)) {
            throw new MergeDataException("Null argument when merging data");
        }

        DataSource addedDs=null;
        String id = DataInfo.getId(ds);

        if (get(id)!=null){    // if data source name already exists then add collection name as a suffix
            String name ="";
            if (ds instanceof CollectiveDataSource){
                name = DataInfo.getLabel(((CollectiveDataSource)ds).getCollection());
          
            } else if (ds instanceof TimeStampedDataSource){
                name = DataInfo.getLabel(((TimeStampedDataSource)ds).getCollection());

            } else {
                try {
                    name = DataInfo.getLabel(DataSourcePool.global.getCollectionForDataSourceId(DataInfo.getId(ds)));
                } catch (DuplicateIdException e) {
                }
            }
            id += "_" + name;
        }
        if (get(id)==null){

            // 1 - Update merged time
            if (timeDs.sortedOrder() != 1) {
                throw new MergeDataException("Cannot add " + DataInfo.getId(ds) + " because its time reference is not sorted");
            }
            updateMergedTimeBounds(timeDs, isRelative, offset, initialDate);

            // 2- Create data source
            addedDs = new DirectSynchronousMergedDataSource(id, this,size(), ds, timeDs, isRelative, offset, initialDate);

            // 4 - Add data source to collection
            addToCollectionArborescence(DataInfo.getId(addedDs), addedDs);
            add(addedDs);
            map.put(id, addedDs);
            sortHugeRepertories();
        }
    }

    /* (non-Javadoc)
     * @see simtools.data.merge.MergeDSCollection#add(simtools.data.async.TimeStampedDataSource)
     */
    public void add(TimeStampedDataSource ds, double offset, double initialDate) throws MergeDataException{
        add(ds, ds.getTime(), false, offset, initialDate);
    }



    /**
     * Apply merge on all collection elements.
     * <ul>
     * <li> If merged element is an indirection, update its phase regarding current merged time range
     * <li> Otherwise, create the buffer that contains interpolated values.
     * </ul>
     */
    public void mergeData() throws MergeDataException{

        // 1- Allocate merged time buffer
        if (mergedTimeLength != -1){
            try {
                final ByteBuffer bb=ByteBuffer.allocateDirect(8*(int)mergedTimeLength);
                mergedTimeBuffer=bb.asDoubleBuffer();  
            } catch (OutOfMemoryError e) {
                removeAllElements();
                throw new MergeDataException("Not enought memory to perform the data merge");
            }
            for(int i=0;i<mergedTimeLength;i++){
                mergedTimeBuffer.put(mergedTimeStart + i*mergedTimeFreq);
            }
           

            // 2. Allocate all other elements buffer
            for(int i=1;i<size();i++){
                DataSource ds = (DataSource)get(i);
               
                if (ds instanceof DirectSynchronousMergedDataSource){
                    try {
                        ((DirectSynchronousMergedDataSource)ds).updateDirectBuffer();
                  
                    } catch (DataException e) {
                        throw new MergeDataException(e.getMessage());
                    } catch (OutOfMemoryError e) {
                        removeAllElements();
                        throw new MergeDataException("Not enought memory to perform the data merge");
                    }
                } else {
                    //TODO: optimization with index indirections ?
                   // ((IndirectSynchronousMergedDataSource)ds).updateDirectBuffer();
                }
            }
        }
    }

   
   
    /**
     *
     * This optimization is no longer used at the moment.
     * @author zxpletran007
     *
     */
    public class IndirectParameter {

        /**
         * The ratio between the merged time frequency (f_mt)  and another time source frequency (f_t) 
         * ratio = f_mt / f_t
         * If ratio is lower than 1, mt is ratio times more frequent than t.
         * If ratio is greater than 1, t is ratio times more frequent than mt.
         *
         * ratio or 1/ratio shall be an integer value, otherwise indirection is not possible for this time source.
          */
        protected final double ratio;
    
        /**
         * The time source first value
         */
        protected final double timeStart;
   
        /**
         * The number of indexes to skip to be phased with collection merge time.
         */
        protected int phase;
       

        /**
         * @param ratio  -
         * 
         * @param timeStart - related time source first value
         *
         * @throws MergeDataException
         */
        public IndirectParameter(double ratio, double timeStart) throws MergeDataException{
            if (ratio <= 0){
                throw new MergeDataException("Invalid ratio value: " +  ratio);
            }
            this.ratio = ratio;
            this.timeStart = timeStart;
        }

        /**
         * Update regarding
         */
        protected void updatePhase() throws MergeDataException{
            double delta =  mergedTimeStart - timeStart;
            if (delta>=0){
                phase= (int)(delta /mergedTimeFreq);
            } else{
                throw new MergeDataException("Invalid time source range");
            }
        }

        public long getIndex(long index){
            if(index<startIndex){
                index=startIndex;
            }
            return (long) Math.round(((index + phase)/ ratio))//TODO check it.
        }

    }
    /**
     * This optimization is no longer used at the moment.
     *
     * A data source dedicated to manage periodical data sources
     * This collective data source provides a indirection to source values,
     * according to a LinearIndirectParameters attribute.
     * @author zxpletran007
     *
     */
    public class IndirectSynchronousMergedDataSource extends CollectiveDataSource{
        protected final DataSource source; 
        protected DataInfo info;
        protected IndirectParameter parameter;

        public IndirectSynchronousMergedDataSource(
                String name,
                DataSourceCollection c,
                int i,
                DataSource source,
                IndirectParameter parameter) throws MergeDataException{
            super(c,i);
            this.source=source;
            this.parameter = parameter;
            setInfo(name);
        }
       
    

        /* (non-Javadoc)
         * @see simtools.data.DataSource#computeMax()
         */
        public Object computeMax() throws UnsupportedOperation {
            return source.computeMax();
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#computeMin()
         */
        public Object computeMin() throws UnsupportedOperation {
            return source.computeMin();
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getMax()
         */
        public Object getMax() throws UnsupportedOperation {
            return source.getMax();
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getMin()
         */
        public Object getMin() throws UnsupportedOperation {
            return source.getMin();
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#sortedOrder()
         */
        public int sortedOrder() {
            return source.sortedOrder();
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getInformation()
         */
        public DataInfo getInformation() {
            info.comment= "Synchronous merge from data source:" + DataInfo.getId(source)
            + "\n Ratio with merged time is: "  + parameter.ratio
            + "\n Phase with merged time is: "  + parameter.phase;

            return info;
        }

        protected void setInfo(String name){
            info=new DataInfo(name);
            info.unit= DataInfo.getUnit(source);
            try{
                //  If data already exists, set extendedLabel with name_collectionName
                if (DataSourcePool.global.getDataSourceWithId(name)!=null){
                    info.extendedLabel=  collectionName;
                }
            }catch (DuplicateIdException e){}
        }
       

        /* (non-Javadoc)
         * @see simtools.data.ValueProvider#getObjectValue(long)
         */
        public Object getObjectValue(long index) throws DataException {
            Object res = null;
           
            if(index<startIndex || index>lastIndex){
                throw new NoSuchIndex(index);
            }
           
            long i = parameter.getIndex(index);

            if (parameter.ratio <= 1){
                res =  source.getValue(i);   // no interpolation needed
       
            } else {
                if (interpolationOrder == 0) {
                    res =  source.getValue(i);

                } else if (interpolationOrder == 1) {

                    long lowerBoundindex = Math.round((i * parameter.ratio) - parameter.phase);
                    long upperBoundindex =  Math.round(( (i+1) * parameter.ratio) - parameter.phase);

                    if (upperBoundindex <= lastIndex){  // it is possible to interpolate

                        //assert that lowerBoundindex <= index <= upperBoundindex
                        if (!( (lowerBoundindex <= index) &&  (index <= upperBoundindex))){
                            throw new DataException("Incorrect interpolation: index= "  + index + " bounds = "  + lowerBoundindex + "; " + upperBoundindex);
                        }

                        double ponderation = (double)(index - lowerBoundindex)/ (upperBoundindex - lowerBoundindex);

                        double lowerBoundValue = source.getDoubleValue(i);
                        double upperBoundValue = source.getDoubleValue(i+1);
                        double interpolatedValue = (1-ponderation)*lowerBoundValue + ponderation*upperBoundValue;

                        res =  new Double(interpolatedValue);

                    } else {
                        res =  source.getValue(i)// no interpolation
                    }
                }
            }
            return res;
        }


        /* (non-Javadoc)
         * @see simtools.data.CollectiveDataSource#getDoubleValue(long)
         */
        public double getDoubleValue(long index) throws DataException {
            Object o = getObjectValue(index);
         
            if (o instanceof Double) {
                return ((Double)o).doubleValue();
            }

            return source.getDoubleValue(parameter.getIndex(index));
        }  

        /* (non-Javadoc)
         * @see simtools.data.CollectiveDataSource#getValue(long)
         */
        public Object getValue(long index) throws DataException {
            return  getObjectValue(index);
        }


        /* (non-Javadoc)
         * @see simtools.data.CollectiveDataSource#getDoubleMax()
         */
        public double getDoubleMax() throws DataException {
            return source.getDoubleMax();
        }

        /* (non-Javadoc)
         * @see simtools.data.CollectiveDataSource#getDoubleMin()
         */
        public double getDoubleMin() throws DataException {
            return source.getDoubleMin();
        }


    }
 
   
    /**
     *  A data source dedicated to manage aperiodical data sources.
     * @author zxpletran007
     */
    public class DirectSynchronousMergedDataSource extends CollectiveDataSource {

        protected DataInfo info;
        protected DataSource source;
        protected DataSource timeRef;

        DoubleBuffer _values;
        Double _min, _max;

        double offset; // number of seconds
        double initialDate;
        boolean isRelative;

        protected DirectSynchronousMergedDataSource(String name, DataSourceCollection c, int i, DataSource source, DataSource timeSource, boolean isRelative, double offset, double initialDate){
            super(c,i);
            setInfo(name);
            this.source = source;
            this.timeRef= timeSource;
            this.isRelative = isRelative;
            this.offset = offset;
            this.initialDate = initialDate;

            _values=null;
            _min=new Double(Double.POSITIVE_INFINITY);
            _max=new Double(Double.NEGATIVE_INFINITY);
        }

        /**
         * Interpolate source values in order to fit with collection time reference.
         * _values _min, _max are updated.
         */
        public void updateDirectBuffer() throws DataException, OutOfMemoryError {
            if (mergedTimeBuffer==null) {
                throw new DataException("Collection time buffer is null, canot create direct buffer for data source " + DataInfo.getId(this));
            }
           
            final ByteBuffer bb=ByteBuffer.allocateDirect(8*mergedTimeBuffer.capacity());
            _values = bb.asDoubleBuffer();

            long trIndex = timeRef.getStartIndex();

            for(long ctIndex=mergedTimeDs.getStartIndex();ctIndex<=mergedTimeDs.getLastIndex();ctIndex++){

                double ctValue = mergedTimeDs.getDoubleValue(ctIndex);

                // Find trIndex 
                while (!(  (trIndex==timeRef.getLastIndex())                                     // last bound
                        || ( (getTimeDoubleValue(trIndex) <= ctValue) && (ctValue < getTimeDoubleValue(trIndex+1)))    // between two values
                        || (getTimeDoubleValue(trIndex) >= ctValue)                              // fisrt
                ))
                    trIndex++;

                if (getTimeDoubleValue(trIndex) > ctValue)  {
                    throw new DataException("Cannot interpolate data source " + DataInfo.getId(this) + " . Its time interval does not match with time reference");
                }
                // Find value
                double interpolatedValue  = source.getDoubleValue(trIndex);

                if ((interpolationOrder==1) && trIndex<timeRef.getLastIndex()){

                    double timeLowerBoundValue  = getTimeDoubleValue(trIndex);
                    double timeUpperBounValue  = getTimeDoubleValue(trIndex+1);

                    double ponderation = (double)(ctValue - timeLowerBoundValue)/ (timeUpperBounValue - timeLowerBoundValue);

                    double lowerBoundValue = source.getDoubleValue(trIndex);
                    double upperBoundValue = source.getDoubleValue(trIndex+1);

                    interpolatedValue = (1-ponderation)*lowerBoundValue + ponderation*upperBoundValue;
                }

                _values.put(interpolatedValue);

                // Update min, max
                if (interpolatedValue>_max.doubleValue()){
                    _max = new Double(interpolatedValue);
                }
                if (interpolatedValue<_min.doubleValue()){
                    _min = new Double(interpolatedValue);
                }
            }
        }

        /**
         * Compute time value for specified index.
         * @param index
         * @return corresponding time value for specified index.
         * @throws DataException
         */
        protected double getTimeDoubleValue(long index)throws DataException{
            double timevalue = timeRef.getDoubleValue(index);
            if (isRelative&& timeRefIsRelative){
                timevalue+=offset;

            }else if (!isRelative&& !timeRefIsRelative){
                timevalue+=offset*1000;

            }else if (!isRelative&& timeRefIsRelative){
                // (ti-t0)/1000 + offset
                timevalue= (timevalue-initialDate)/1000.0 + offset;

            }else if (isRelative&& !timeRefIsRelative){
                // initialDate + ti*1000 + offset*1000
                timevalue= initialDate + timevalue*1000.0 + offset*1000.0;
            }
            return timevalue;
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#computeMax()
         */
        public Object computeMax() throws UnsupportedOperation {
            if (_max==null)
                throw new UnsupportedOperation("Error on max value on direct data source " + DataInfo.getId(source));
            return _max;
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#computeMin()
         */
        public Object computeMin() throws UnsupportedOperation {
            if (_min==null)
                throw new UnsupportedOperation("Error on min value on direct data source " + DataInfo.getId(source));
            return _min;
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getMax()
         */
        public Object getMax() throws UnsupportedOperation {
            return computeMax();
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getMin()
         */
        public Object getMin() throws UnsupportedOperation {
            return computeMin();
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#sortedOrder()
         */
        public int sortedOrder() {
            return source.sortedOrder();
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getInformation()
         */
        public DataInfo getInformation() {
            return info;
        }

        protected void setInfo(String name){
            info=new DataInfo(name);
            info.unit= DataInfo.getUnit(source);
            info.comment= "Synchronous merge from aperiodical data source:" + DataInfo.getId(source)
            + "\n Offset =" + offset ;

            info.extendedLabel= collectionName;
        }


        /* (non-Javadoc)
         * @see simtools.data.ValueProvider#getObjectValue(long)
         */
        public Object getObjectValue(long index) throws DataException {
            if(index<startIndex || index>lastIndex){
                throw new NoSuchIndex(index);
            }
            if (_values==null)
                throw new DataException("Null buffer on direct data source " + DataInfo.getId(source));

            return new Double(_values.get((int)index));
        }


        /* (non-Javadoc)
         * @see simtools.data.CollectiveDataSource#getDoubleValue(long)
         */
        public double getDoubleValue(long index) throws DataException {
            if(index<startIndex || index>lastIndex){
                throw new NoSuchIndex(index);
            }
            if (_values==null)
                throw new DataException("Null buffer on direct data source " + DataInfo.getId(source));

            return _values.get((int)index);
       

        /* (non-Javadoc)
         * @see simtools.data.CollectiveDataSource#getValue(long)
         */
        public Object getValue(long index) throws DataException {
            return  getObjectValue(index);
        }

        /* (non-Javadoc)
         * @see simtools.data.CollectiveDataSource#getDoubleMax()
         */
        public double getDoubleMax() throws DataException {
            return ((Double)getMax()).doubleValue();
        }

        /* (non-Javadoc)
         * @see simtools.data.CollectiveDataSource#getDoubleMin()
         */
        public double getDoubleMin() throws DataException {
            return ((Double)getMin()).doubleValue();
        }
    }

    public class TimeSource extends DataSource {

        protected DataInfo di=new DataInfo("mergedTime","mergedTime");

        /* (non-Javadoc)
         * @see simtools.data.DataSource#computeMax()
         */
        public Object computeMax() throws UnsupportedOperation {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));
            return new Double(mergedTimeBuffer.get((int)lastIndex));
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#computeMin()
         */
        public Object computeMin() throws UnsupportedOperation {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));
            return new Double(mergedTimeBuffer.get((int)startIndex));
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getMax()
         */
        public Object getMax() throws UnsupportedOperation {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));
            return new Double(mergedTimeBuffer.get((int)lastIndex));
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getMin()
         */
        public Object getMin() throws UnsupportedOperation {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));
            return new Double(mergedTimeBuffer.get((int)startIndex));
        }

        /* (non-Javadoc)
         * @see simtools.data.ValueProvider#getDoubleValue(long)
         */
        public double getDoubleValue(long index) throws DataException {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));

            if(index<startIndex || index>lastIndex){
                throw new NoSuchIndex(index);
            }
            return mergedTimeBuffer.get((int)index);
        }


        /* (non-Javadoc)
         * @see simtools.data.ValueProvider#getObjectValue(long)
         */
        public Object getObjectValue(long index) throws DataException {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));

            if(index<startIndex || index>lastIndex){
                throw new NoSuchIndex(index);
            }
            return new Double(mergedTimeBuffer.get((int)index));
        }


        /* (non-Javadoc)
         * @see simtools.data.DataSource#getDoubleMax()
         */
        public double getDoubleMax() throws DataException {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));

            return mergedTimeBuffer.get((int)lastIndex);
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getDoubleMin()
         */
        public double getDoubleMin() throws DataException {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));

            return mergedTimeBuffer.get((int)startIndex);
        }

        /* (non-Javadoc)
         * @see simtools.data.ValueProvider#getValue(long)
         */
        public Object getValue(long index) throws DataException {
            if (mergedTimeBuffer==null)
                throw new UnsupportedOperation("Null buffer on time data source: " + DataInfo.getId(this));

            if(index<startIndex || index>lastIndex){
                throw new NoSuchIndex(index);
            }
            return new Double(mergedTimeBuffer.get((int)index));
        }

        public long getStartIndex() throws UnsupportedOperation {
            return startIndex;
        }

        public long getLastIndex() throws UnsupportedOperation {
            return lastIndex;
        }


        /* (non-Javadoc)
         * @see simtools.data.DataSource#sortedOrder()
         */
        public int sortedOrder() {
            return 1;
        }

        /* (non-Javadoc)
         * @see simtools.data.DataSource#getInformation()
         */
        public DataInfo getInformation() {
            return di;
        }
    }

    public boolean isCompound() {
        return true;
    }

    public Collection getCollectionContainers() {
        return collectionRoot.getChildren();
    }

    public class MergedCollectionContainer extends Container {

        /**
         * Create a new container with the given value
         */
        public MergedCollectionContainer(String value) {
            super(value);
            children  = new ArrayList()
        }

        public Collection getChildren(){
            return children;
        }
        public void setChildren(Collection c){
            children =c;
        }

        protected MergedCollectionContainer getChildCollection(String childName){
            Object o;
            for (Iterator iter = children.iterator(); iter.hasNext(); ) {
                o = iter.next();
                if (o instanceof MergedCollectionContainer){
                    MergedCollectionContainer c = (MergedCollectionContainer)o;
                    if (c.value.equals(childName))
                        return c;
                }
            }
            return null;
        }

        protected void removeCollectionArborescence(){
            Object o;
            for (Iterator iter = children.iterator(); iter.hasNext(); ) {
                o = iter.next();
                if (o instanceof MergedCollectionContainer)
                    ((MergedCollectionContainer)o).removeCollectionArborescence();
            }
            children.clear();
       
    }

    protected void addToCollectionArborescence(String name, DataSource d){
        MergedCollectionContainer currentDirectory = collectionRoot;
        String prefixe, sufixe;
        int lengthNameModel = name.indexOf(".");

        // Placement de la DS dans une collection fille
        while( lengthNameModel!=-1) {
            prefixe = name.substring(0, lengthNameModel);
            sufixe = name.substring(lengthNameModel+1,name.length());

            MergedCollectionContainer subCollection =  (MergedCollectionContainer)currentDirectory.getChildCollection(prefixe);
            if (subCollection==null){
                MergedCollectionContainer  lastDirectory = new MergedCollectionContainer(prefixe);
                currentDirectory.addContainer(lastDirectory);
                currentDirectory = lastDirectory;
            }
            else {
                currentDirectory =   subCollection;
            }
            name = sufixe;
            lengthNameModel = name.indexOf(".");
        }
        // Ajout du suffixe comme nouvelle dataSource du container courant
        d.getInformation().label = name;

        currentDirectory.addDataSource(d);
    }

    protected void sortHugeRepertories(){ 
        // We compute all 2nd levels -> ex :  PL.*
        if ( ((collectionRoot.getChildren().iterator().hasNext()) &&(collectionRoot.getChildren().iterator().next()) instanceof MergedCollectionContainer)){
            Collection subRoots = ((MergedCollectionContainer)(collectionRoot.getChildren().iterator().next())).getChildren();
            Object o;
            for (Iterator iter = subRoots.iterator(); iter.hasNext(); ) {
                o = iter.next();
                if (o instanceof MergedCollectionContainer){
                    sortHugeRepertory((MergedCollectionContainer)o, 2);
                }
            }
        }
    }

    /**
     * @param repertory , where data source have to be structured
     * @param proof,  number of prefixes to remove from all data sources names,  in order to compute the new structure.
     * Ex : if PL.TM.variable -> proof = 2
     */
    protected void sortHugeRepertory(MergedCollectionContainer repertory, int proof){
        Object o;
        int count =0;
        String start=null;
        int diff=0;
        for (Iterator iter = repertory.getChildren().iterator(); iter.hasNext(); ) {
            o = iter.next();
            if (o instanceof DataSource) {
                String dsName = ((DataSource)o).getInformation().id;
                String repName = dsName.substring(dsName.indexOf(".")+1);       
                for(int i =0;i<proof-1;i++){
                    repName = repName.substring(repName.indexOf(".")+1);
                }
                if(start==null){
                    start=repName.substring(0,repName.length()>2 ? 3 : repName.length());
                }
                else{
                    if(!repName.startsWith(start)){
                        diff++;
                    }
                }
                count++;
            }
        }
        if (count > HUGEREPERTORYSIZE && diff>0){
            Hashtable newRepositories = new Hashtable();
            ArrayList dataList = new ArrayList(repertory.getChildren());
            for (Iterator iter = repertory.getChildren().iterator(); iter.hasNext(); ) {
                o = iter.next();
                if (o instanceof DataSource){
                    DataSource d = (DataSource)o;
                    String dsName = ((d.getInformation().id));
                    String repName = dsName.substring(dsName.indexOf(".")+1);

                    for(int i =0;i<proof-1;i++){
                        repName = repName.substring(repName.indexOf(".")+1);
                    }
                    repName = repName.substring(0,1);
                    MergedCollectionContainer  rep;
                    if (newRepositories.containsKey(repName)){
                        rep = (MergedCollectionContainer)newRepositories.get(repName);
                    }else{
                        rep = new MergedCollectionContainer(repName);
                        newRepositories.put(repName, rep);
                        dataList.add(rep);
                   
                    rep.addDataSource(d);
                    dataList.remove(d);
                }
            }
            repertory.setChildren(dataList);
        }
    }



    /* (non-Javadoc)
     * @see simtools.data.DataSourceCollection#getMax(int)
     */
    public Object getMax(int i) throws UnsupportedOperation {
        return ((DataSource)get(i)).getMax();
    }

    /* (non-Javadoc)
     * @see simtools.data.DataSourceCollection#getMin(int)
     */
    public Object getMin(int i) throws UnsupportedOperation {
        return ((DataSource)get(i)).getMin();
    }

    /* (non-Javadoc)
     * @see simtools.data.DataSourceCollection#computeMax(int)
     */
    public Object computeMax(int i) throws UnsupportedOperation {
        return ((DataSource)get(i)).computeMax();
    }

    /* (non-Javadoc)
     * @see simtools.data.DataSourceCollection#computeMin(int)
     */
    public Object computeMin(int i) throws UnsupportedOperation {
        return ((DataSource)get(i)).computeMin();
    }

    /* (non-Javadoc)
     * @see simtools.data.DataSourceCollection#getValue(int, long)
     */
    public Object getValue(int i, long index) throws DataException {
        return ((DataSource)get(i)).getValue(index);
    }

    /* (non-Javadoc)
     * @see simtools.data.DataSourceCollection#getDoubleValue(int, long)
     */
    public double getDoubleValue(int i, long index) throws DataException {
        return ((DataSource)get(i)).getDoubleValue(index);
    }

    /* (non-Javadoc)
     * @see simtools.data.DataSourceCollection#getInformation(int)
     */
    public DataInfo getInformation(int i) {
        return ((DataSource)get(i)).getInformation();
    }

    /* (non-Javadoc)
     * @see simtools.data.DataSourceCollection#valueClass(int)
     */
    public Class valueClass(int i) {
        return Double.class;
    }

    public DataInfo getInformation() {
        return new DataInfo(collectionName, ID_MARKER+collectionName, "Synchronous merge");
    }

    public String getCollectionName(){
        return collectionName;
    }

}
TOP

Related Classes of simtools.data.merge.SynchronousMergeDSCollection$MergedCollectionContainer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.