// ---------------------------------------------------------------------- // // HepHist1D.cc - implementation of generic one-dimensional histogram // // HepHist1D is a generic one-dimensional histogram. It is derived from // HepHist, and its final implementation is defined by a manager class/ // histogram subclass. HepHist1D provides methods for filling a // histogram and retreiving information from and about it. // // HepHist1D 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]; // : // : // HepHist1D & h(m->hist1D("Histogram Title", 100, 0.0, 23.0)); // float x, weight; // : // [gather data] // : // h->accumulate(x, weight); // // // Note that the constructor can take an ID number which is used by // some implementations of HepHist1D. 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 HepHist1D 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 proper comments from HepHist1D.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 // 21-Feb-2000 Walter Brown Improved C++ standard compliance // // ---------------------------------------------------------------------- #ifndef HEPTRACE_H #include "HepTuple/HepTrace.h" #endif #ifndef HEPFILEMANAGER_H #include "HepTuple/HepFileManager.h" #endif #ifndef HEPHIST1D_H #include "HepTuple/HepHist1D.h" #endif #ifndef HEPRAWHIST_H #include "HepTuple/HepRawHist.h" #endif #include "ZMutility/iostream" #include "ZMutility/cmath" USING( namespace std ) ZM_BEGIN_NAMESPACE( zmht ) /* namespace zmht { */ // type identifier ( is equal to type() for this object ) const char HepHist1D::typeId = '1'; #define BADCALL(fctnName) \ ZMthrow(ZMxHepUnsupported(" your 1-D histogram class does not support the "\ #fctnName " call.")); // create a 1D histogram with the given title and binning HepHist1D::HepHist1D( HepFileManager * manager , const string& title , const int nBins, const float low, const float high , const int id_req ) : HepHist( manager, title, id_req ) , _nBins( nBins ) , _min ( low ) , _max ( high ) { HEP_DEBUG( "HepHist1D::constructor( \"" << title << "\", " << id_ << " )" ); type_ = '1'; } // Used for dummy construction ... // the object is then not valid ... HepHist1D::HepHist1D() : HepHist() , _nBins( 0 ) , _min ( 0 ) , _max ( 0 ) { HEP_DEBUG( "HepHist1D::constructor( )" ); type_ = '1'; } HepHist1D::~HepHist1D() { HEP_DEBUG( "HepHist1D::destructor( \"" << *title_ << "\", " << id_ << " )" ); } void HepHist1D::accumulate( const float x , const float weight ) { BADCALL(accumulate(xValue,weight)); } void HepHist1D::_accumulate( const float x , const float weight ) { if ( manager()->isReadOnly() ) { ZMthrow(ZMxHepCantWriteFile( manager()->fileName() + " is read only. Can not fill histogram." )); } else { isDirty( true ); } } void HepHist1D::reset() { BADCALL(reset()); } float HepHist1D::bin( const int binNum ) const { BADCALL(bin(binNum)); return 0.0; } float HepHist1D::binError( const int binNum ) const { BADCALL(binError(binNum)); return 0.0; } void HepHist1D::getContents( float * values ) const { BADCALL(getContents(values)); } void HepHist1D::putContents( float * values ) const { BADCALL(putContents(values)); } void HepHist1D::getErrors( float * errors ) const { BADCALL(getErrors(errors)); } void HepHist1D::putErrors( float * errors ) const { BADCALL(putErrors(errors)); } void HepHist1D::getStatistics( int & numEntries , float & sumW , float & sumW2 , double & sumWX , double & sumWX2 ) const { BADCALL(getStatistics(arglist)); } void HepHist1D::getOverflows( float * numOver , float * numUnder ) const { BADCALL(getOverflows(numOver,numUnder)); } void HepHist1D::setXTitle( const std::string& label ) { BADCALL(setXTitle(label)); } void HepHist1D::setYTitle( const std::string& label ) { BADCALL(setYTitle(label)); } void HepHist1D::setZTitle( const std::string& label ) { BADCALL(setZTitle(label)); } HepRawHist HepHist1D::importHist1D( const HepHist1D & h ) { BADCALL(importHist1D(HepHist1D & h)); int nullid = 0; HepRawHist dummy = HepRawHist( nullid ); return dummy; } void HepHist1D::addHist1D( const HepRawHist & h ) { BADCALL(addHist1D(HepRawHist & h)); } void HepHist1D::subtractHist1D( const HepRawHist & h ) { BADCALL(subtractHist1D(HepRawHist & h)); } void HepHist1D::multiplyHist1D( const HepRawHist & h ) { BADCALL(multiplyHist1D(HepRawHist & h)); } void HepHist1D::divideHist1D( const HepRawHist & h ) { BADCALL(divideHist1D(HepRawHist & h)); } void HepHist1D::removeImportedHist1D( const HepRawHist & h ) { BADCALL(removeImportedHist1D(HepRawHist & h)); } int HepHist1D::nBins() const { // retrieve # of in-range X bins return _nBins; } float HepHist1D::min() const { // retrieve low end of binned X range return _min; } float HepHist1D::max() const { // retrieve high end of binned X range return _max; } int HepHist1D::entries() const { // number of entries BADCALL(entries()); return 0; } float HepHist1D::weight() const { // sum of all weight BADCALL(weight()); return 0.0; } float HepHist1D::weight2() const { // sum of all weight BADCALL(weight2()); return 0.0; } float HepHist1D::sum() const { // retrieve weighted sum BADCALL(sum()); return 0.0; } float HepHist1D::sum2() const { // retrieve weighted sum of square (X^2) BADCALL(sum2()); return 0.0; } ZM_COVARIANT_TYPE(HepObj,HepHist1D) & HepHist1D::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->deadHist1D(); } // Static cast for platform without covariant return type for virtual member function HepHist1D & clone = static_cast ( makeEmpty( manager, title, id ) ); clone += *this; return clone; } ZM_COVARIANT_TYPE(HepObj,HepHist1D) & HepHist1D::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->deadHist1D(); } return mgr->hist1D( title, nBins(), min(), max(), id ); } ZM_COVARIANT_TYPE(HepObj,HepHist1D) & HepHist1D::makeClone( // clone existing histogram, filling bins const string& title , const int id ) const { return makeClone( manager(), title, id ); } ZM_COVARIANT_TYPE(HepObj,HepHist1D) & HepHist1D::makeEmpty( // clone existing histogram, but zero bins const string& title , const int id ) const { return makeEmpty( manager(), title, id ); } bool HepHist1D::compatibleHist1D ( const HepHist1D & h ) { // First check that the two histogram objects are accessible. float maxDiff = 1.0e-6f; 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 = nBins(); // Number of in-range bins in *this int numBins2 = h.nBins(); // Number of in-range bins in h if( numBins1 != numBins2 ) { ZMthrow(ZMxHepIncompatible( string("Histograms do not have the same number of bins."))); return false; } float minX1 = min(); // Low end of range for *this float maxX1 = max(); // High end of range for *this float minX2 = h.min(); // Low end of range for h float maxX2 = h.max(); // High end of 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; } return true; } HepHist1D & HepHist1D::operator += ( const HepHist1D & h ) { // Check that the two histogram objects are compatible. if( !compatibleHist1D( 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 //inplementation of *this. // The manager-dependent method instantiates an unmanaged histogram object // of the right type via a call to HepHist1D and then fills it so that it is // equivalent to h but in the implementation of *this HepRawHist temp = importHist1D( h ); if( temp.isValid() ) { // Now the thing identified by temp and *this are in the same implementation. // Pass them to another manager-dependent method that uses the methods within // that implementation to combine them according to it's rules. addHist1D( temp ); isDirty( true ); // Still need to go to the appropriate descendant method to delete // the RawHist object. It's still lying around. removeImportedHist1D( temp ); } return *this; } HepHist1D & HepHist1D::operator -= ( const HepHist1D & h ) { // Check that the two histogram objects are compatible. if( !compatibleHist1D( 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 //inplementation of *this. // The manager-dependent method instantiates an unmanaged histogram object // of the right type via a call to HepHist1D and then fills it so that it is // equivalent to h but in the implementation of *this HepRawHist temp = importHist1D( h ); if( temp.isValid() ) { // Now the thing identified by temp and *this are in the same implementation. // Pass them to another manager-dependent method that uses the methods within // that implementation to combine them according to it's rules. subtractHist1D( temp ); isDirty( true ); // Still need to go to the appropriate descendant method to delete // the RawHist object. It's still lying around. removeImportedHist1D( temp ); } return *this; } HepHist1D & HepHist1D::operator *= ( const HepHist1D & h ) { // Check that the two histogram objects are compatible. if( !compatibleHist1D( 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 //inplementation of *this. // The manager-dependent method instantiates an unmanaged histogram object // of the right type via a call to HepHist1D and then fills it so that it is // equivalent to h but in the implementation of *this HepRawHist temp = importHist1D( h ); if( temp.isValid() ) { // Now the thing identified by temp and *this are in the same implementation. // Pass them to another manager-dependent method that uses the methods within // that implementation to combine them according to it's rules. multiplyHist1D( temp ); isDirty( true ); // Still need to go to the appropriate descendant method to delete // the RawHist object. It's still lying around. removeImportedHist1D( temp ); } return *this; } HepHist1D & HepHist1D::operator /= ( const HepHist1D & h ) { // Check that the two histogram objects are compatible. if( !compatibleHist1D( 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 //inplementation of *this. // The manager-dependent method instantiates an unmanaged histogram object // of the right type via a call to HepHist1D and then fills it so that it is // equivalent to h but in the implementation of *this HepRawHist temp = importHist1D( h ); if( temp.isValid() ) { // Now the thing identified by temp and *this are in the same implementation. // Pass them to another manager-dependent method that uses the methods within // that implementation to combine them according to it's rules. divideHist1D( temp ); isDirty( true ); // Still need to go to the appropriate descendant method to delete // the RawHist object. It's still lying around. removeImportedHist1D( temp ); } return *this; } ZM_END_NAMESPACE( zmht ) /* } // namespace zmht */