// ---------------------------------------------------------------------- // // HepHist2D.cc - implementation of generic two-dimensional histogram // // HepHist2D is a generic two-dimensional histogram. It is derived from // HepHist, and its final implementation is defined by a manager class/ // histogram subclass. HepHist2D provides methods for filling a // histogram and retreiving information from and about it. // // HepHist2D objects are not directly instantiated. Instead, the manager // creates the object using its own implementation of the histogram. // // Typical usage: // // HepFileManager* m = new [define the manager]; // : // : // HepHist2D & h(m->hist2D("Title", 100, 0.0, 2.0, 100, 0.0, 2.0)); // float x, y, weight; // : // [gather data] // : // h->accumulate(x, y, weight); // // // Note that the constructor can take an ID number which is used by // some implementations of HepHist2D. If omitted, the ID number is // generated automatically (which is recommended). The ID number is // available through the id() method. // // Most of the methods in HepHist2D do nothing more than generate an // error when called. It is up to the manager-specific derived class to // implement the appropriate ones. // // // History: // ??-???-19?? Bob Jacobsen Initial draft, based on ideas in HepTuple // and the SLT histogram classes of Joe Boudreau // 05-May-1997 Walter Brown Initial design & draft of Hist class // 22-May-1997 Walter Brown Merged Hist into HepHistogram // 30-May-1997 Walter Brown Added cloning functions // 29-May-1997 Jason Luther Added comments // 04-Jun-1997 Jason Luther Added comments from HepHist2D.h // 30-Jul-1998 Philippe Canal Added typeId // 04-Aug-1998 Philippe Canal Added weight, entries, sum, etc.. // 25-Feb-1999 J. Marraffino Added increment operators for histograms // // ---------------------------------------------------------------------- #ifndef HEPTRACE_H #include "HepTuple/HepTrace.h" #endif #ifndef HEPFILEMANAGER_H #include "HepTuple/HepFileManager.h" #endif #ifndef HEPHIST2D_H #include "HepTuple/HepHist2D.h" #endif #ifndef HEPRAWHIST_H #include "HepTuple/HepRawHist.h" #endif #include "ZMutility/iostream" #include USING( std::string ) ZM_BEGIN_NAMESPACE( zmht ) /* namespace zmht { */ // type identifier ( is equal to type() for this object ) const char HepHist2D::typeId = '2'; #define BADCALL(fctnName) \ ZMthrow(ZMxHepUnsupported(" your 2-D histogram class does not support the "\ #fctnName " call.")); // create a 2D histogram with the given title and binning HepHist2D::HepHist2D( HepFileManager * manager , const string& title , const int nBinsX, const float lowX, const float highX , const int nBinsY, const float lowY, const float highY , const int id_req ) : HepHist( manager, title, id_req ) , _nBinsX( nBinsX ) , _minX ( lowX ) , _maxX ( highX ) , _nBinsY( nBinsY ) , _minY ( lowY ) , _maxY ( highY ) { HEP_DEBUG( "HepHist2D::constructor( \"" << title << "\", " << id_ << " )" ); type_ = '2'; } // Used for dummy construction ... // the object is then not valid ... HepHist2D::HepHist2D() : HepHist() , _nBinsX(0 ) , _minX (0 ) , _maxX (0 ) , _nBinsY(0 ) , _minY (0 ) , _maxY (0 ) { HEP_DEBUG( "HepHist2D::constructor( )" ); type_ = '2'; } HepHist2D::~HepHist2D() { HEP_DEBUG( "HepHist2D::destructor( \"" << *title_ << "\", " << id_ << " )" ); } void HepHist2D::accumulate( const float xValue , const float yValue , const float weight ) { BADCALL(accumulate(xValue,yValue,weight)); } void HepHist2D::_accumulate( const float xValue , const float yValue , const float weight ) { if ( manager()->isReadOnly() ) { ZMthrow(ZMxHepCantWriteFile( manager()->fileName() + " is read only. Can not fill histogram." )); } else { isDirty( true ); } } void HepHist2D::reset() { BADCALL(reset); } float HepHist2D::bin( const int binNumX, const int binNumY ) const { BADCALL(bin(binNumX,binNumY)); return 0.0; } int HepHist2D::nBinsX() const { // retrieve # of in-range X bins return _nBinsX; } int HepHist2D::nBinsY() const { // retrieve # of in-range Y bins return _nBinsY; } float HepHist2D::minX() const { // retrieve low end of binned X range return _minX; } float HepHist2D::minY() const { // retrieve high end of binned X range return _minY; } float HepHist2D::maxX() const { // retrieve low end of binned X range return _maxX; } float HepHist2D::maxY() const { // retrieve high end of binned X range return _maxY; } int HepHist2D::entries() const { // Number of entries in bins BADCALL(entries); return 0; } float HepHist2D::weight() const { // Sum of all weights BADCALL(weight); return 0.0; } float HepHist2D::weight2() const { // Sum of all weights BADCALL(weight2); return 0.0; } float HepHist2D::sumX() const { // retrieve weighted sum of X BADCALL(sumX); return 0.0; } float HepHist2D::sumY() const { // retrieve weighted sum of Y BADCALL(sumY); return 0.0; } float HepHist2D::sumX2() const { // retrieve weighted sum of X^2 BADCALL(sumX2); return 0.0; } float HepHist2D::sumXY() const { // retrieve weighted sum of X*Y BADCALL(sumXY); return 0.0; } float HepHist2D::sumY2() const { // retrieve weighted sum of Y^2 BADCALL(sumY2); return 0.0; } float HepHist2D::binError( int binNumX , int binNumY ) const { BADCALL(binError(binNumX,binNumY)); return 0.0; } void HepHist2D::getContents( float * values ) const { BADCALL(getContents(values)); } void HepHist2D::putContents( float * values ) const { BADCALL(putContents(values)); } void HepHist2D::getErrors( float * errors ) const { BADCALL(getErrors(errors)); } void HepHist2D::putErrors( float * errors ) const { BADCALL(putErrors(errors)); } void HepHist2D::getStatistics( int & numEntries , float & sumW , float & sumW2 , double & sumWX , double & sumWX2 ) const { BADCALL(getStatistics(arglist)); } void HepHist2D::getOverflows( float * numXOverYOver , float * numXOverYUnder , float * numXUnderYUnder , float * numXUnderYOver , float * numTop , float * numRight , float * numBottom , float * numLeft ) const { BADCALL(getOverflows(arglist)); } void HepHist2D::setXTitle( const std::string& label ) { BADCALL(setXTitle(label)); } void HepHist2D::setYTitle( const std::string& label ) { BADCALL(setYTitle(label)); } void HepHist2D::setZTitle( const std::string& label ) { BADCALL(setZTitle(label)); } void HepHist2D::setTitle( const std::string& label ) { BADCALL(setTitle(label)); } HepRawHist HepHist2D::importHist2D( const HepHist2D & h ) { BADCALL(importHist2D(HepHist2D & h)); int nullid = 0; HepRawHist dummy = HepRawHist( nullid ); return dummy; } void HepHist2D::addHist2D( const HepRawHist & h ) { BADCALL(addHist2D(HepRawHist & h)); } void HepHist2D::multiplyHist2D( const HepRawHist & h ) { BADCALL(multiplyHist2D(HepRawHist & h)); } void HepHist2D::subtractHist2D( const HepRawHist & h ) { BADCALL(subtractHist2D(HepRawHist & h)); } void HepHist2D::divideHist2D( const HepRawHist & h ) { BADCALL(divideHist2D(HepRawHist & h)); } bool HepHist2D::compatibleHist2D( const HepHist2D & h ) { float maxDiff = 1.0e-6f; // First check that the two histogram objects are accessible. if( !mayUse() || !h.mayUse() ) { ZMthrow(ZMxHepUnmanagedItem( string("attempt to manipulate one or more unmanaged histograms."))); return false; } // And Check that the this histogram can be modified if ( manager()->isReadOnly() ) { ZMthrow(ZMxHepCantWriteFile( manager()->fileName() + " is read only. Can not modify the " + title() + " histogram." )); return false; } // Check that the two histogram objects are compatible -- this means // they have the same number of bins and span the same range. int numBins1 = nBinsX() * nBinsY(); // Number of in-range bins in *this int numBins2 = h.nBinsX()*h.nBinsY(); // Number of in-range bins in h if( numBins1 != numBins2 ) { ZMthrow(ZMxHepIncompatible( string("Histograms do not have the same number of bins."))); return false; } // Check X ranges first float minX1 = minX(); // Low end of X range for *this float maxX1 = maxX(); // High end of X range for *this float minX2 = h.minX(); // Low end of X range for h float maxX2 = h.maxX(); // High end of X range for h float deltaXLow = minX2 - minX1; float deltaXHigh = maxX2 - maxX1; // Make this work for both Kai and gcc. That means don't use abs()! float absDeltaXLow = ( deltaXLow > 0.0 ? deltaXLow : -deltaXLow ); float absDeltaXHigh = ( deltaXHigh > 0.0 ? deltaXHigh : -deltaXHigh ); if(( absDeltaXLow > maxDiff ) || ( absDeltaXHigh > maxDiff )) { ZMthrow(ZMxHepIncompatible( string("Histograms do not have the same range."))); return false; } // Then check Y ranges float minY1 = minY(); // Low end of Y range for *this float maxY1 = maxY(); // High end of Y range for *this float minY2 = h.minY(); // Low end of Y range for h float maxY2 = h.maxY(); // High end of Y range for h float deltaYLow = minY2 - minY1; float deltaYHigh = maxY2 - maxY1; // Make this work for both Kai and gcc. That means don't use abs()! float absDeltaYLow = ( deltaYLow > 0.0 ? deltaYLow : -deltaYLow ); float absDeltaYHigh = ( deltaYHigh > 0.0 ? deltaYHigh : -deltaYHigh ); if(( absDeltaYLow > maxDiff ) || ( absDeltaYHigh > maxDiff ) ) { ZMthrow(ZMxHepIncompatible( string("Histograms do not have the same range."))); return false; } return true; } void HepHist2D::removeImportedHist2D( const HepRawHist & h ) { BADCALL(removeImportedHist2D(HepRawHist & h)); } HepHist2D & HepHist2D::operator += ( const HepHist2D & h ) { // Check that the two histogram objects are compatible if( !compatibleHist2D( h ) ) return *this; // Check that there are some entries already int numEntries = h.entries(); // Number of entries in h // If h is empty, we're done already if( numEntries == 0 ) return *this; // Otherwise, set up to combine histograms. First convert h to the // implementation of *this. HepRawHist temp = importHist2D( h ); if( temp.isValid() ) { addHist2D( temp ); isDirty( true ); removeImportedHist2D( temp ); } return *this; } HepHist2D & HepHist2D::operator -= ( const HepHist2D & h ) { // Check that the two histogram objects are compatible if( !compatibleHist2D( h ) ) return *this; // Check that there are some entries already int numEntries = h.entries(); // Number of entries in h // If h is empty, we're done already if( numEntries == 0 ) return *this; // Otherwise, set up to combine histograms. First convert h to the // implementation of *this. HepRawHist temp = importHist2D( h ); if( temp.isValid() ) { subtractHist2D( temp ); isDirty( true ); removeImportedHist2D( temp ); } return *this; } HepHist2D & HepHist2D::operator *= ( const HepHist2D & h ) { // Check that the two histogram objects are compatible if( !compatibleHist2D( h ) ) return *this; // Check that there are some entries already int numEntries = h.entries(); // Number of entries in h // If h is empty, we're done already if( numEntries == 0 ) return *this; // Otherwise, set up to combine histograms. First convert h to the // implementation of *this. HepRawHist temp = importHist2D( h ); if( temp.isValid() ) { multiplyHist2D( temp ); isDirty( true ); removeImportedHist2D( temp ); } return *this; } HepHist2D & HepHist2D::operator /= ( const HepHist2D & h ) { // Check that the two histogram objects are compatible if( !compatibleHist2D( h ) ) return *this; // Check that there are some entries already int numEntries = h.entries(); // Number of entries in h // If h is empty, we're done already if( numEntries == 0 ) return *this; // Otherwise, set up to combine histograms. First convert h to the // implementation of *this. HepRawHist temp = importHist2D( h ); if( temp.isValid() ) { divideHist2D( temp ); isDirty( true ); removeImportedHist2D( temp ); } return *this; } ZM_COVARIANT_TYPE(HepObj,HepHist2D) & HepHist2D::makeClone( // clone existing histogram, filling bins HepFileManager * manager , const string& title , const int id ) const { if ( ! mayUse() ) { ZMthrow(ZMxHepUnmanagedItem( string("attempt to makeClone() to unmanaged histogram ") +title+string("."))); return manager->deadHist2D(); } // Static cast for platform without covariant return type for virtual member function HepHist2D & clone = static_cast ( makeEmpty( manager, title, id ) ); clone += *this; return clone; } ZM_COVARIANT_TYPE(HepObj,HepHist2D) & HepHist2D::makeEmpty( // clone existing histogram, but zero bins HepFileManager * mgr , const string& title , const int id ) const { if ( ! mayUse() ) { ZMthrow(ZMxHepUnmanagedItem( string("attempt to makeEmpty() to unmanaged histogram ") +title+string("."))); return mgr->deadHist2D(); } return mgr->hist2D( title, nBinsX(), minX(), maxX(), nBinsY(), minY(), maxY(), id ); } ZM_COVARIANT_TYPE(HepObj,HepHist2D) & HepHist2D::makeClone( // clone existing histogram, filling bins const string& title , const int id ) const { return makeClone( manager(), title, id ); } ZM_COVARIANT_TYPE(HepObj,HepHist2D) & HepHist2D::makeEmpty( // clone existing histogram, but zero bins const string& title , const int id ) const { return makeEmpty( manager(), title, id ); } ZM_END_NAMESPACE( zmht ) /* } // namespace zmht */