package hep.aida.ref.histogram;
/**
* Implementation of ICloud1D.
* @author The AIDA team at SLAC.
*
*/
import hep.aida.ICloud1D;
import hep.aida.IHistogram;
import hep.aida.IHistogram1D;
import java.util.ArrayList;
public class Cloud1D extends Cloud implements ICloud1D {
/**
* Create a new Cloud1D
*/
public Cloud1D() {
super("","",1,0,"");
}
/**
* Create a new Cloud1D
* @param name The Cloud's name.
* @param title The Cloud's title.
* @param nMax The maximum number of entries stored in the Cloud. If nMax is greater than zero the Cloud
* will be converted to an Histogram when the number of entries is more than nMax.
* @param options Some options.
*
*/
protected Cloud1D(String name,String title,int nMax,String options) {
super(name,title,1,nMax,options);
}
/**
* Fill the Cloud with a new value with unit weight
* @param value The value to add to the Cloud.
* @return <code>true</code> if the fill was successful.
*
*/
public void fill(double value) {
fill(value,1.0);
}
/**
* Fill the Cloud with a new value with given weight
* @param value The value to add to the Cloud.
* @param weight The value's weight.
* @return <code>true</code> if the fill was successful.
*
*/
public void fill(double value, double weight) {
if (nEntries == 0) {
lowerEdge = upperEdge=value;
}
else {
if (value<lowerEdge) lowerEdge=value;
if (value>upperEdge) upperEdge=value;
}
if ( histo != null ) {
histo.fill(value,weight);
} else if ( autoConvert() && nEntries == maxEntries ) {
if ( histo != null ) throw new RuntimeException("Cloud already been converted");
histo= toShowableHistogram(conversionBins(), conversionLowerEdge(), conversionUpperEdge());
histo.fill(value,weight);
values = null;
weights = null;
valuesArray.clear();
weightsArray.clear();
valuesArray = null;
weightsArray = null;
} else {
if ( nEntries%arraySize == 0 ) {
values = new double[ arraySize ];
weights = new double[ arraySize ];
valuesArray.add( values );
weightsArray.add( weights );
}
values[ nEntries%arraySize ] = value;
weights[ nEntries%arraySize ] = weight;
if ( ( !Double.isNaN(value) ) && ( !Double.isNaN(weight) ) ) {
sumOfWeights += weight;
mean += value*weight;
rms += value*value*weight;
validEntries++;
}
nEntries++;
// if ( nEntries > maxEntries && maxEntries > 0 ) throw new IllegalArgumentException();
}
if (isValid) fireStateChanged();
}
/**
* Get the Cloud's lower edge.
* @return The Cloud's lower edge.
*
*/
public double lowerEdge() {
return lowerEdge;
}
/**
* Get the Cloud's upper edge.
* @return The Cloud's upper edge.
*
*/
public double upperEdge() {
return upperEdge;
}
/**
* Set the Cloud's upper edge
* @param upperEdge The Cloud's upper edge.
*
*/
public void setUpperEdge( double upperEdge ) {
this.upperEdge = upperEdge;
}
/**
* Set the Cloud's lower edge
* @param lowerEdge The Cloud's lower edge.
*
*/
public void setLowerEdge( double lowerEdge ) {
this.lowerEdge = lowerEdge;
}
/**
* Get a given value from the Cloud.
* @param index The value's index.
* @return The Cloud's corresponding value.
* @exception RuntimeException if the Cloud has been converted
*
*/
public double value(int index) {
if (histo!=null) throw new RuntimeException("Cloud has been converted");
double[] val = (double[])valuesArray.get( index/arraySize );
return val[index%arraySize];
}
/**
* Get a given weight from the Cloud.
* @param index The weight's index.
* @return The Cloud's corresponding weight.
* @exception RuntimeException if the Cloud has been converted
*
*/
public double weight(int index) {
if (histo!=null) throw new RuntimeException("Cloud has been converted");
double[] val = (double[])weightsArray.get( index/arraySize );
return val[index%arraySize];
}
/**
* Get the Cloud's mean.
* @return The Cloud's mean.
*
*/
public double mean() {
if ( histo != null ) return histo.mean();
return mean / sumOfWeights();
}
/**
* Get the Cloud's rms.
* @return The Cloud's rms.
*
*/
public double rms() {
if ( histo != null ) return histo.rms();
return Math.sqrt( rms / sumOfWeights() - mean*mean/sumOfWeights()/sumOfWeights() );
}
/**
* Get the Cloud's entries.
* @return The Cloud's entries.
*
*/
public int entries() {
if ( histo != null ) return histo.allEntries();
return nEntries;
}
/**
* Represent the Cloud as a Histogram.
* @param nBins The Histogram's number of bins.
* @param lowerEdge The Histogram's lower edge.
* @param upperEdge The Histogram's upper edge.
* @return The Histogram representing the Cloud.
*
*/
private IHistogram1D toShowableHistogram(int nBins, double lowerEdge, double upperEdge) {
if ( histo != null ) return histo;
return HistUtils.toShowableHistogram(this, nBins, lowerEdge, upperEdge);
}
/**
* Convert the ICloud to an IHistogram.
*
*/
public void convert(int nBins, double lowerEdge, double upperEdge) {
if ( histo != null ) throw new RuntimeException("Cloud already been converted");
histo= toShowableHistogram(nBins, lowerEdge, upperEdge);
if (isValid) fireStateChanged();
}
/**
* Convert the ICloud to an IHistogram by specifying the bin edges.
*
*/
public void convert( double[] binEdges ) {
if ( histo != null ) throw new RuntimeException("Cloud already been converted");
IHistogram1D hist = new Histogram1D(name(),title(),new VariableAxis(binEdges));
for(int i=0; i<nEntries; i++) hist.fill( value(i), weight(i) );
histo = hist;
if (isValid) fireStateChanged();
}
/**
* Has the Cloud been converted to a Histogram?
* @return <code>true<\code> if the Cloud has been converted to a Histogram.
*
*/
public boolean isConverted() {
return histo != null ? true : false;
}
/**
* Get the Histogram representing the Cloud
* @return the histogram.
* @exception RuntimeException if the histogram is not auto-convertible and "convert"
* has not been called.
*/
public IHistogram1D histogram() throws RuntimeException {
if ( histo == null ) throw new RuntimeException("Cloud has not been converted");
return histo;
}
/**
* Set the Histogram representation of the Cloud.
* @param hist The Histogram representing the Cloud.
*
*/
public void setHistogram( IHistogram1D hist ) {
if ( histo != null ) throw new RuntimeException("Cloud already been converted");
histo = hist;
if (isValid) fireStateChanged();
}
public void fillHistogram(hep.aida.IHistogram1D hist1d) {
if ( histo != null ) throw new IllegalArgumentException("Cloud has already been converted");
for(int i=0; i<nEntries; i++) hist1d.fill( value(i), weight(i) );
}
public void reset() {
nEntries = 0;
lowerEdge = Double.NaN;
upperEdge = Double.NaN;
mean = 0.;
rms = 0.;
sumOfWeights = 0.;
if ( histo != null )
histo.reset();
histo = null;
valuesArray = new ArrayList();
weightsArray = new ArrayList();
values = null;
weights = null;
super.reset();
}
public void convertToHistogram() {
if ( histo != null ) throw new IllegalArgumentException("Cloud has already been converted to an Histogram");
histo = toShowableHistogram(conversionBins(), conversionLowerEdge(), conversionUpperEdge());
if (isValid) fireStateChanged();
}
public void scale(double scaleFactor) throws IllegalArgumentException {
if ( scaleFactor <= 0 ) throw new IllegalArgumentException("Illegal scale factor "+scaleFactor+" it has to be positive");
if ( isConverted() ) histo.scale( scaleFactor );
else {
for ( int i = 0; i < entries(); i++ ) {
double[] weights = (double[])weightsArray.get( i/arraySize );
weights[i%arraySize] *= scaleFactor;
}
sumOfWeights *= scaleFactor;
mean *= scaleFactor;
rms *= scaleFactor;
}
if (isValid) fireStateChanged();
}
/** Get the sum of weights of of all the entries
* @return The sum of the weights of all the entries.
*
*/
public double sumOfWeights() {
if ( histo != null ) return histo.sumAllBinHeights();
return sumOfWeights;
}
public double lowerEdgeWithMargin() {
if ( Double.isNaN(lowerEdge) )
return Double.NaN;
double le = lowerEdge != upperEdge ? lowerEdge : lowerEdge - 1;
double ue = lowerEdge != upperEdge ? upperEdge : upperEdge + 1;
double delta = ue - le;
return le - margin()*Math.abs(delta);
}
public double upperEdgeWithMargin() {
if ( Double.isNaN(upperEdge) )
return Double.NaN;
double le = lowerEdge != upperEdge ? lowerEdge : lowerEdge - 1;
double ue = lowerEdge != upperEdge ? upperEdge : upperEdge + 1;
double delta = ue - le;
return ue + margin()*Math.abs(delta);
}
protected IHistogram hist() {
return (IHistogram) histogram();
}
/**
* Set the parameters for the ICloud conversion to an IHistogram.
* @param bins The number of bins of the conversion IHistogram.
* @param lowerEdge The lower edge of the conversion IHistogram.
* @param upperEdge The upper edge of the conversion IHistogram.
*
*/
public void setConversionParameters(int bins, double lowerEdge, double upperEdge) {
this.convBins = bins;
this.convLowerEdge = lowerEdge;
this.convUpperEdge = upperEdge;
}
public int conversionBins() {
return convBins;
}
public double conversionLowerEdge() {
if ( Double.isNaN(convLowerEdge) )
return lowerEdgeWithMargin();
return convLowerEdge;
}
public double conversionUpperEdge() {
if ( Double.isNaN(convUpperEdge) )
return upperEdgeWithMargin();
return convUpperEdge;
}
private int nEntries=0;
private double lowerEdge = Double.NaN, upperEdge = Double.NaN;
protected double sumOfWeights;
private double mean, rms;
private IHistogram1D histo;
private ArrayList valuesArray = new ArrayList();
private ArrayList weightsArray = new ArrayList();
private double[] values, weights;
private int convBins = 50;
private double convLowerEdge = Double.NaN;
private double convUpperEdge = Double.NaN;
}