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