#ifndef _utl_TimeDistribution_h_ #define _utl_TimeDistribution_h_ /** \file Histogram class for time distributions with suppressed empty bins. Includes two iterator types: 1) SparseIterator steps through time slots skipping those for which values were never assigned. \author Tom Paul \version $Id: TimeDistribution.h 18664 2011-02-16 14:53:32Z darko $ \date 22 Mar 2004 */ static const char CVSId_utl_TimeDistribution[] = "$Id: TimeDistribution.h 18664 2011-02-16 14:53:32Z darko $"; #include #include #include #include #include #include namespace utl { class TimeDistributionAlgorithm; /** \class TimeDistribution TimeDistribution.h "sevt/TimeDistribution.h" \brief Histogram class for time distributions with suppressed empty bins. \author Tom Paul and Darko Veberic \date 28 April 2004 \date 23 July 2006 DV update to boost::transform_iterator \version $Id: TimeDistribution.h 18664 2011-02-16 14:53:32Z darko $ \ingroup time stl */ template class TimeDistribution { private: typedef std::map InternalMap; typedef typename InternalMap::value_type InternalMapValue; typedef typename InternalMap::iterator InternalIterator; typedef typename InternalMap::const_iterator InternalConstIterator; public: typedef T ValueType; typedef boost::tuple Tuple; struct InternalMapFunctor { Tuple operator()(const InternalMapValue& pair) const { return Tuple(pair.first, pair.second); } }; /** Sparse iteration skips bins with no content. Here is a code snippet illustrating iteration through sparse bins \code TimeDistributionI timeDist; // Fill the timeDist with data for (TimeDistributionI::SparseIterator it = timeDist.SparseBegin(); it != timeDist.SparseEnd(); ++it) { cout << "time (ns) = " << it->get<0>() / nanosecond << ", value = " << it->get<1>() << endl; } \endcode */ typedef boost::transform_iterator SparseIterator; /// Constructor takes the bin size as an argument TimeDistribution(const double slotSize) : fSlotSize(slotSize) { } /// Remove contents of the TimeDistribution void Clear() { fData.clear(); } /// Remove empty slots and return their number int Purge() { int n = 0; for (InternalIterator it = fData.begin(); it != fData.end(); ) { if (it->second == T()) { Erase(it++); ++n; } else ++it; } return n; } /// Add an entry (optionally weighted) in the given slot. The slot may be negative. void AddTime(const int slot, const T weight = T(1)) { if (weight) { const InternalIterator it = fData.find(slot); if (it == fData.end()) fData[slot] = weight; else { it->second += weight; if (!it->second) fData.erase(it); } } } /// Add an entry (optionally weighted) for the given time. Slot will be computed. /*! The bin to increment will be computed based on the bin size */ void AddTime(const double time, const T weight = T(1)) { AddTime(int(std::floor(time/fSlotSize)), weight); } void SetTime(const int slot, const T weight = T(1)) { if (weight) fData[slot] = weight; else { const InternalIterator it = fData.find(slot); if (it != fData.end()) fData.erase(it); } } void SetTime(const double time, const T weight = T(1)) { SetTime(int(std::floor(time/fSlotSize)), weight); } /// Return slot content. /** If no slot exists for requested index, create new slot and initialize to 0. */ T& operator[](const int index) { return fData[index]; } /// Return slot content. /** Slight optimization for const case. Does not create new slots, returns reference to zero in case of a miss. */ const T& operator[](const int index) const { static const T zero = T(0); const InternalConstIterator it = fData.find(index); return it == fData.end() ? zero : it->second; } /// Query value without slot creation T At(const int index) const { const InternalConstIterator it = fData.find(index); return it == fData.end() ? 0 : it->second; } /// Return contents for slot containing the specified time /** If no slot exists for requested index, create a new slot and initialize to 0. */ T& operator[](const double time) { return operator[](int(std::floor(time/fSlotSize))); } const T& operator[](const double time) const { return operator[](int(std::floor(time/fSlotSize))); } T At(const double time) const { return At(int(std::floor(time/fSlotSize))); } /// Add two traces. Adds only bins that have data in them. TimeDistribution operator+(const TimeDistribution& td) const { if (GetBinning() == td.GetBinning()) { TimeDistribution val(*this); for (InternalConstIterator it = td.fData.begin(); it != td.fData.end(); ++it) val[it->first] += it->second; return val; } else { const std::string msg("Cannot add two TimeDistributions with unequal binning."); ERROR(msg); throw AugerException(msg); // not sure what kind of exception to throw here. } } bool operator==(const TimeDistribution& td) const { return fSlotSize == td.fSlotSize && fData == td.fData; } bool operator!=(const TimeDistribution& td) const { return !operator==(td); } /// Size of one slot double GetBinning() const { return fSlotSize; } /// First slot with data int GetStart() const { return fData.empty() ? 0 : fData.begin()->first; } /// Last slot with data (1 less than First slot if no data) int GetStop() const { return fData.empty() ? -1 : fData.rbegin()->first; } /// Number of slots from first slot with data up to last slot with data, including empty slots. int GetNumSlots() const { return fData.empty() ? 0 : fData.rbegin()->first - fData.begin()->first + 1; } /// Iterator over time slots with data in them (skips empty slots). SparseIterator SparseBegin() const { return SparseIterator(fData.begin()); } SparseIterator SparseEnd() const { return SparseIterator(fData.end()); } private: void Erase(const InternalIterator it) { fData.erase(it); } InternalMap fData; double fSlotSize; friend class TimeDistributionAlgorithm; }; typedef TimeDistribution TimeDistributionD; typedef TimeDistribution TimeDistributionI; } // utl #endif // _utl_TimeDistribution_h_ // Configure (x)emacs for this file ... // Local Variables: // mode: c++ // End: