|
[yoda-svn] r470 - in trunk: . include/YODA srcblackhole at projects.hepforge.org blackhole at projects.hepforge.orgFri Jun 15 19:25:00 BST 2012
Author: buckley Date: Fri Jun 15 19:25:00 2012 New Revision: 470 Log: Histo2D reintroduced into compilation, and 2D classes cut down until compilation works (plus some consistency/minimalisation tidying). Work on implementing Axis2D etc. can now start in earnest. Modified: trunk/TODO trunk/include/YODA/Axis1D.h trunk/include/YODA/Axis2D.h trunk/include/YODA/Bin1D.h trunk/include/YODA/Bin2D.h trunk/include/YODA/Histo2D.h trunk/include/YODA/HistoBin1D.h trunk/include/YODA/HistoBin2D.h trunk/include/YODA/ProfileBin1D.h trunk/include/YODA/ProfileBin2D.h trunk/include/YODA/ReaderYODA.h trunk/src/Histo2D.cc trunk/src/Makefile.am Modified: trunk/TODO ============================================================================== --- trunk/TODO Fri May 4 11:03:33 2012 (r469) +++ trunk/TODO Fri Jun 15 19:25:00 2012 (r470) @@ -21,6 +21,8 @@ * Improve tests Makefile setup to work out the path to the Python build dir. (AB) +* Remove nasty Cython shims (DM) + NEXT Modified: trunk/include/YODA/Axis1D.h ============================================================================== --- trunk/include/YODA/Axis1D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/Axis1D.h Fri Jun 15 19:25:00 2012 (r470) @@ -19,21 +19,25 @@ class Axis1D { public: - /// Convenience typedefs + /// Typedefs + //@{ + + /// Bin type typedef BIN1D Bin; - /// A vector containing 1D bins. It is not used for searching, - /// only for bins storage. - typedef typename std::vector<BIN1D> Bins; + /// A vector containing 1D bins. Not used for searching. + typedef typename std::vector<Bin> Bins; - /// Type used to implement a search table of low bin edges mapped to bin indices. + /// @brief Type used to implement a search table of low bin edges mapped to bin indices. /// An index of -1 indicates a gap interval, without a corresponding bin. typedef std::map<double, long int> BinHash; + //@} + + /// @name Constructors //@{ - /// Empty constructor Axis1D() { } @@ -45,6 +49,7 @@ /// Constructor with the number of bins and the axis limits + /// @todo Rewrite interface to use a pair for the low/high Axis1D(size_t nbins, double lower, double upper) { _addBins(linspace(lower, upper, nbins)); } @@ -170,7 +175,7 @@ long int getBinIndex(double coord) const { // First check that we are within the axis bounds at all if (coord < lowEdge() || coord > highEdge()) return -1; - // Then return the lower-edge lookup from the hash map + // Then return the lower-edge lookup from the hash map. // NB. both upper_bound and lower_bound return values *greater* than (or equal) to coord, // so we have to step back one iteration to get to the lower-or-equal containing bin edge. BinHash::const_iterator itabove = _binhash.upper_bound(coord); @@ -361,11 +366,13 @@ } } + /// Check if there are any bin edges between values @a from and @a to. bool _edgeInRange(double from, double to) const { return (--_binhash.upper_bound(from)) != (--_binhash.lower_bound(to)); } + /// Check if there are any gaps in the axis' binning between bin indices @a from and @a to, inclusive. bool _gapInRange(size_t ifrom, size_t ito) const { assert(ifrom < numBins() && ito < numBins() && ifrom <= ito); @@ -390,7 +397,7 @@ /// Total distribution DBN _dbn; - /// Under- and over- flows + /// Under- and overflows DBN _underflow; DBN _overflow; Modified: trunk/include/YODA/Axis2D.h ============================================================================== --- trunk/include/YODA/Axis2D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/Axis2D.h Fri Jun 15 19:25:00 2012 (r470) @@ -24,90 +24,66 @@ /// workings. template <typename BIN2D, typename DBN> class Axis2D { + public: - /// @name Internal typedefs + /// @name Typedefs //@{ - /// When an edge is added to the collection it must obey the following - /// format: the size_t specifies the bin this edge is a member of, and the - /// pair of doubles contains the beginning and end of the edge. - typedef typename std::pair<size_t, std::pair<double,double> > Edge; - - /// A type being a basic substructure of _binHashSparse. It contains a indicator - /// specifying the major coordinate and a collection of edges sharing the same major - /// coordinate. - typedef typename std::pair<double, std::vector<Edge> > EdgeCollection; - - /// A simple point in 2D - typedef typename std::pair<double, double> Point; - - /// Segment, having a beginning and end. - typedef typename std::pair<Point, Point> Segment; - - //@} - - - public: - - // A few helpful typedefs + /// Bin type typedef BIN2D Bin; - /// @brief The internal bin container type - /// - /// The following vector holds in itself an information about a Bin and a - /// state in which it is. If the state is set to be false the bin will not - /// be displayed and in effect will be treated as non-existent. The most - /// common situation when such a functionality is needed is when merging a - /// bin. For detailed description about what happens in such case, please - /// refer to the mergeBins() function. + /// The internal bin container type. Not used for searching. typedef typename std::vector<Bin> Bins; + /// @brief Type used to implement a search table of low bin edges (in 2D) mapped to bin indices. + /// An index of -1 indicates a gap interval, without a corresponding bin. + typedef std::map<double, int> SubBinHash; + typedef std::map<double, SubBinHash> BinHash; + + //@} - public: /// @name Constructors: //@{ - /// @brief Empty constructor - /// - /// Only added because it is required by SWIG. - /// It doesn't make much sense to use it. - /// @todo Really "required"? Eliminate the requirement in the SWIG mapping. - Axis2D() { - std::vector<Segment> edges; - _mkAxis(edges); - } + /// Empty constructor + Axis2D() {} /// Most standard constructor accepting X/Y ranges and number of bins - /// on each of the axis. Both Axis are divided linearly. + /// on each of the axis. Both axes are divided linearly. + /// @todo Rewrite interface to use pairs for the low/high Axis2D(size_t nbinsX, double lowerX, double upperX, size_t nbinsY, double lowerY, double upperY) { - std::vector<Segment> binLimits; - double coeffX = (upperX - lowerX)/(double)nbinsX; - double coeffY = (upperY - lowerX)/(double)nbinsY; - for (double i = lowerX; i < upperX; i += coeffX) { - for (double j = lowerY; j < upperY; j += coeffY) { - binLimits.push_back(std::make_pair(std::make_pair(i, j), - std::make_pair((double)(i+coeffX), (double)(j+coeffY)))); - } - } - _mkAxis(binLimits); - _setOutflows(); + /// @todo TODO + + // std::vector<Segment> binLimits; + // double coeffX = (upperX - lowerX)/(double)nbinsX; + // double coeffY = (upperY - lowerX)/(double)nbinsY; + // for (double i = lowerX; i < upperX; i += coeffX) { + // for (double j = lowerY; j < upperY; j += coeffY) { + // binLimits.push_back(std::make_pair(std::make_pair(i, j), + // std::make_pair((double)(i+coeffX), (double)(j+coeffY)))); + // } + // } + // _mkAxis(binLimits); + // _setOutflows(); } /// A constructor with specified x and y axis bin limits. Axis2D(const std::vector<double>& xedges, const std::vector<double>& yedges) { - std::vector<Segment> binLimits; - /// Generate bin limits - for (size_t i = 0; i < yedges.size() - 1; ++i) { - for (size_t j = 0; j < xedges.size() - 1; ++j) { - binLimits.push_back(std::make_pair(std::make_pair(xedges[j], yedges[i]), - std::make_pair(xedges[j+1], yedges[i+1]))); - } - } - _mkAxis(binLimits); - _setOutflows(); + /// @todo TODO + + // std::vector<Segment> binLimits; + // /// Generate bin limits + // for (size_t i = 0; i < yedges.size() - 1; ++i) { + // for (size_t j = 0; j < xedges.size() - 1; ++j) { + // binLimits.push_back(std::make_pair(std::make_pair(xedges[j], yedges[i]), + // std::make_pair(xedges[j+1], yedges[i+1]))); + // } + // } + // _mkAxis(binLimits); + // _setOutflows(); } /// @brief A constructor accepting a list of bins and all the outflows @@ -117,53 +93,53 @@ const std::vector<std::vector<DBN> >& outflows, const DBN& totalDbn) { - std::vector<Segment> binLimits; - foreach(Bin bin, bins) { - binLimits.push_back(std::make_pair(std::make_pair(bin.xMin(), bin.yMin()), - std::make_pair(bin.xMax(), bin.yMax()))); - } - _mkAxis(binLimits); - for (size_t i = 0; i < _bins.size(); ++i) { - _bins[i] = bins[i]; - } - if (isGrid()) _setOutflows(); - _outflows = outflows; + /// @todo TODO + + // std::vector<Segment> binLimits; + // foreach(Bin bin, bins) { + // binLimits.push_back(std::make_pair(std::make_pair(bin.xMin(), bin.yMin()), + // std::make_pair(bin.xMax(), bin.yMax()))); + // } + // _mkAxis(binLimits); + // for (size_t i = 0; i < _bins.size(); ++i) { + // _bins[i] = bins[i]; + // } + // if (isGrid()) _setOutflows(); + // _outflows = outflows; - _dbn = totalDbn; + // _dbn = totalDbn; } - /// A constructor accepting just a list of bins - Axis2D(const Bins& bins) + + /// Constructor accepting just a list of bins + Axis2D(const Bins& bins) { - std::vector<Segment> binLimits; - foreach(Bin bin, bins) { - binLimits.push_back(std::make_pair(std::make_pair(bin.xMin(), bin.yMin()), - std::make_pair(bin.xMax(), bin.yMax()))); - } - _mkAxis(binLimits); - for (size_t i = 0; i < _bins.size(); ++i) { - _bins[i] = bins[i]; - } - if (isGrid()) _setOutflows(); + /// @todo TODO + + // std::vector<Segment> binLimits; + // foreach(Bin bin, bins) { + // binLimits.push_back(std::make_pair(std::make_pair(bin.xMin(), bin.yMin()), + // std::make_pair(bin.xMax(), bin.yMax()))); + // } + // _mkAxis(binLimits); + // for (size_t i = 0; i < _bins.size(); ++i) { + // _bins[i] = bins[i]; + // } + // if (isGrid()) _setOutflows(); } - /// A copy constructor + + /// Copy constructor Axis2D(const Axis2D& a) { _bins = a._bins; _dbn = a._dbn; _outflows = a._outflows; - _binHashSparse.first.regenCache(); - _binHashSparse.second.regenCache(); - } - - /// Constructor provided with a vector of bin delimiters - Axis2D(const std::vector<Segment>& binLimits) { - _mkAxis(binLimits); - if (isGrid()) _setOutflows(); + /// @todo TODO + // _binHashSparse.first.regenCache(); + // _binHashSparse.second.regenCache(); } - //@} @@ -172,28 +148,14 @@ /// @brief Bin addition operator /// - /// This operator is provided a vector of limiting points in the format - /// required by _mkAxis(). It should be noted that there is nothing special - /// about the initiation stage of Axis2D, and the edges can be added online - /// if they meet all the requirements of non-degeneracy. - /// - /// Be aware that adding a Bin to an existing axis created by one of - /// constructors wipes out all the outflows since a concept of them is no - /// longer meaningful! - void addBin(const std::vector<Segment>& binLimits) { - _mkAxis(binLimits); - _outflows.resize(0); - } - - /// @brief Bin addition operator - /// /// This operator is supplied with the extremal coordinates of just a new /// bin, which is then constructed and added as usual. void addBin(double lowX, double lowY, double highX, double highY) { - std::vector<Segment> coords; - coords.push_back(std::make_pair(std::make_pair(lowX, lowY), - std::make_pair(highX, highY))); - addBin(coords); + /// @todo TODO + // std::vector<Segment> coords; + // coords.push_back(std::make_pair(std::make_pair(lowX, lowY), + // std::make_pair(highX, highY))); + // addBin(coords); } //@} @@ -202,146 +164,115 @@ /// @name Modifiers //@{ - /// @brief Fill operator in 2D - /// - /// Called when it is wanted to fill a certain position on an Axis - int fill(double x, double y, double weight) { - // Filling the total distribution - _dbn.fill(x, y, weight); - - // Filling a bin if the coordinates point to one. - int index = getBinIndex(x, y); - if (index != -1) _bins[index].fill(x, y, weight); - - // If coordinates point outside any of the bins and and the outflows were - // properly set (i.e. we are dealing with a grid), fill a proper outflow. - else if (_outflows.size() == 8) _fillOutflows(x, y, weight); - - // Return an information regarding what was filled. - return index; - } - - /// @brief Fill operator for the 3D case - /// For a detailed description, please see the 2D one. - int fill(double x, double y, double z, double weight) { - _dbn.fill(x, y, z, weight); - - int index = getBinIndex(x,y); - if (index != -1) _bins[index].fill(x, y, z, weight); - - else if (_outflows.size() == 8) _fillOutflows(x, y, z, weight); - return index; - } - - - - /// Merge a range of bins, given the bin IDs of points at the lower-left and upper-right. - void mergeBins(size_t from, size_t to) { - /// Acquire the starting/ending bins - BIN2D& start = bin(from); - BIN2D& end = bin(to); - - /// Set the bin to be added as a starting bin - /// and then remove the unneeded starting bin from - /// the list of bins. - BIN2D temp = start; - eraseBin(from); - - // Sanity-check of input indices - if (start.midpoint().first > end.midpoint().first) { - throw RangeError("The start bin has a greater x value than the end bin."); - } - if (start.midpoint().second > end.midpoint().second) { - std::cout << "Start: " << start.midpoint().second; - std::cout << " end: " << end.midpoint().second << std::endl; - throw RangeError("The start bin has a greater y value than the end bin."); - } - - /// Create a vector that will contain indexes of bins that - /// will be removed after merging them with our 'main' bin. - std::vector<size_t> toRemove; - - /// Look for lower/upper limit of the merge function operation. - /// i.e.: search for index of lowEdgeY of starting bin in _binHashSparse - /// and lowEdgeY of ending bin. This way we don't have to scroll through all - /// the bins to check which ones we have to add. - for (size_t y = (*_binHashSparse.first._cache.lower_bound(start.yMin())).second; - y <= (*_binHashSparse.first._cache.lower_bound(end.yMin())).second; ++y) { - /// For all the bins that are in the bounds specified in previous for - for (size_t x = 0; x < _binHashSparse.first[y].second.size(); ++x) { - /// If the bin lies in a rectangle produced by starting and ending bins - /// (ie. the one spanned by lower-left point of starting bin and top-right - /// point of ending bin) and was not merged already: - if (((_binHashSparse.first[y].second[x].second.first > start.xMin() || - fuzzyEquals(_binHashSparse.first[y].second[x].second.first, start.xMin())) && - (_binHashSparse.first[y].second[x].second.second < end.xMax() || - fuzzyEquals(_binHashSparse.first[y].second[x].second.second, end.xMax())))&& - !(std::find(toRemove.begin(), toRemove.end(), _binHashSparse.first[y].second[x].first) != toRemove.end())) - { - /// Merge it with the temp bin and mark it as ready for removal - temp += bin(_binHashSparse.first[y].second[x].first); - toRemove.push_back(_binHashSparse.first[y].second[x].first); - } - } - } + // /// Merge a range of bins, given the bin IDs of points at the lower-left and upper-right. + // /// @todo TODO + // void mergeBins(size_t from, size_t to) { + // /// Acquire the starting/ending bins + // BIN2D& start = bin(from); + // BIN2D& end = bin(to); + + // /// Set the bin to be added as a starting bin + // /// and then remove the unneeded starting bin from + // /// the list of bins. + // BIN2D temp = start; + // eraseBin(from); + + // // Sanity-check of input indices + // if (start.midpoint().first > end.midpoint().first) { + // throw RangeError("The start bin has a greater x value than the end bin."); + // } + // if (start.midpoint().second > end.midpoint().second) { + // std::cout << "Start: " << start.midpoint().second; + // std::cout << " end: " << end.midpoint().second << std::endl; + // throw RangeError("The start bin has a greater y value than the end bin."); + // } + + // /// Create a vector that will contain indexes of bins that + // /// will be removed after merging them with our 'main' bin. + // std::vector<size_t> toRemove; + + // /// Look for lower/upper limit of the merge function operation. + // /// i.e.: search for index of lowEdgeY of starting bin in _binHashSparse + // /// and lowEdgeY of ending bin. This way we don't have to scroll through all + // /// the bins to check which ones we have to add. + // for (size_t y = (*_binHashSparse.first._cache.lower_bound(start.yMin())).second; + // y <= (*_binHashSparse.first._cache.lower_bound(end.yMin())).second; ++y) { + // /// For all the bins that are in the bounds specified in previous for + // for (size_t x = 0; x < _binHashSparse.first[y].second.size(); ++x) { + // /// If the bin lies in a rectangle produced by starting and ending bins + // /// (ie. the one spanned by lower-left point of starting bin and top-right + // /// point of ending bin) and was not merged already: + // if (((_binHashSparse.first[y].second[x].second.first > start.xMin() || + // fuzzyEquals(_binHashSparse.first[y].second[x].second.first, start.xMin())) && + // (_binHashSparse.first[y].second[x].second.second < end.xMax() || + // fuzzyEquals(_binHashSparse.first[y].second[x].second.second, end.xMax())))&& + // !(std::find(toRemove.begin(), toRemove.end(), _binHashSparse.first[y].second[x].first) != toRemove.end())) + // { + // /// Merge it with the temp bin and mark it as ready for removal + // temp += bin(_binHashSparse.first[y].second[x].first); + // toRemove.push_back(_binHashSparse.first[y].second[x].first); + // } + // } + // } + + // /// Now, drop the bins to be dropped + // /// Keeping in mind that the bins must be removed from the highest index + // /// down, otherwise we will end up removing other bins that we intend to + // std::sort(toRemove.begin(), toRemove.end()); + // std::reverse(toRemove.begin(), toRemove.end()); + // foreach(size_t remove, toRemove) eraseBin(remove); + + // /// Add edges of our merged bin to _binHashSparse and don't create a default + // /// empty bin. + // _addEdge(temp.edges(), _binHashSparse, false); + + // /// Add the actual merged bin to the Axis. + // _bins.push_back(temp); + + + + // /// And regenerate the caches on _binHashSparse + // _binHashSparse.first.regenCache(); + // _binHashSparse.second.regenCache(); + // } + + // /// Merge a range of bins giving start and end coordinates + // void mergeBins(double startX, double startY, double endX, double endY) { + // mergeBins(binByCoord(startX, startY), binByCoord(endX, endY)); + // } + + // /// Rebin by an interger factor + // /// NOT YET WORKING!!11!!1111 + // void rebin(size_t factorX, size_t factorY) { + // if (!isGrid()) throw GridError("Rebinning by a factor can only act on full grids!"); + // if(factorX < 1 || factorY < 1) throw RangeError("Factors cannot be smaller than unity!"); + + // size_t binsInColumn = _binHashSparse.first.size() - 1; + + // std::cout << std::endl << "Bins in column: " << binsInColumn << std::endl; + // std::cout << "Number of bins: " << _bins.size() << std::endl; + // size_t startIndex = 0; + // while(true) { + // size_t endIndex = startIndex; + // for(size_t i = 1; i < factorY; ++i){ + // if(_hasAbove(endIndex) == 1) endIndex++; + // else break; + // } + // binsInColumn -= endIndex - startIndex; + // for(size_t i = 1; i < factorX; ++i){ + // if(endIndex + binsInColumn < _bins.size()) endIndex += binsInColumn; + // else break; + // } + // if(endIndex + 1 >= _bins.size()) break; + // mergeBins(startIndex, endIndex); + // if(startIndex + 1 < _bins.size()) startIndex++; + // else break; - /// Now, drop the bins to be dropped - /// Keeping in mind that the bins must be removed from the highest index - /// down, otherwise we will end up removing other bins that we intend to - std::sort(toRemove.begin(), toRemove.end()); - std::reverse(toRemove.begin(), toRemove.end()); - foreach(size_t remove, toRemove) eraseBin(remove); - - /// Add edges of our merged bin to _binHashSparse and don't create a default - /// empty bin. - _addEdge(temp.edges(), _binHashSparse, false); - - /// Add the actual merged bin to the Axis. - _bins.push_back(temp); - - - - /// And regenerate the caches on _binHashSparse - _binHashSparse.first.regenCache(); - _binHashSparse.second.regenCache(); - } - - /// Merge a range of bins giving start and end coordinates - void mergeBins(double startX, double startY, double endX, double endY) { - mergeBins(binByCoord(startX, startY), binByCoord(endX, endY)); - } - - /// Rebin by an interger factor - /// NOT YET WORKING!!11!!1111 - void rebin(size_t factorX, size_t factorY) { - if (!isGrid()) throw GridError("Rebinning by a factor can only act on full grids!"); - if(factorX < 1 || factorY < 1) throw RangeError("Factors cannot be smaller than unity!"); - - size_t binsInColumn = _binHashSparse.first.size() - 1; - - std::cout << std::endl << "Bins in column: " << binsInColumn << std::endl; - std::cout << "Number of bins: " << _bins.size() << std::endl; - size_t startIndex = 0; - while(true) { - size_t endIndex = startIndex; - for(size_t i = 1; i < factorY; ++i){ - if(_hasAbove(endIndex) == 1) endIndex++; - else break; - } - binsInColumn -= endIndex - startIndex; - for(size_t i = 1; i < factorX; ++i){ - if(endIndex + binsInColumn < _bins.size()) endIndex += binsInColumn; - else break; - } - if(endIndex + 1 >= _bins.size()) break; - mergeBins(startIndex, endIndex); - if(startIndex + 1 < _bins.size()) startIndex++; - else break; + // if(_hasAbove(startIndex-1) == 0) binsInColumn = _binHashSparse.first.size() -1; + // } - if(_hasAbove(startIndex-1) == 0) binsInColumn = _binHashSparse.first.size() -1; - } + // } - } /// Reset the axis statistics void reset() { @@ -365,33 +296,37 @@ /// Get the number of bins along X axis const size_t numBinsX() const { - return _binHashSparse.second.size()/2; + return (numBins() > 0) ? _binhash.size() : 0; } /// Get the number of bins along Y axis const size_t numBinsY() const { - return _binHashSparse.first.size()/2; + return (numBins() > 0) ? _binhash.begin()->second.size() : 0; } /// Get the value of the lowest x-edge on the axis const double lowEdgeX() const { - return _binHashSparse.second.front().first; + if (numBins() == 0) throw RangeError("This axis contains no bins and so has no defined range"); + return _binhash.begin()->first; } /// Get the value of the highest x-edge on the axis const double highEdgeX() const { - return _binHashSparse.second.back().first; + if (numBins() == 0) throw RangeError("This axis contains no bins and so has no defined range"); + return (--_binhash.end())->first; } /// Get the value of the lowest y-edge on the axis const double lowEdgeY() const { - return _binHashSparse.first.front().first; + if (numBins() == 0) throw RangeError("This axis contains no bins and so has no defined range"); + return _binhash.begin()->second.begin()->first; } /// Get the value of the highest y-edge on the axis const double highEdgeY() const { - return _binHashSparse.first.back().first; + if (numBins() == 0) throw RangeError("This axis contains no bins and so has no defined range"); + return (--_binhash.begin()->second.end())->first; } @@ -435,15 +370,15 @@ /// Get a bin at given coordinates (non-const version) BIN2D& binByCoord(double x, double y) { const int ret = getBinIndex(x, y); - if (ret != -1) return bin(ret); - else throw RangeError("No bin found!!"); + if (ret == -1) throw RangeError("No bin found!!"); + return bin(ret); } /// Get a bin at given coordinates (const version) const BIN2D& binByCoord(double x, double y) const { const int ret = getBinIndex(x, y); - if (ret != -1) return bin(ret); - else throw RangeError("No bin found!!"); + if (ret == -1) throw RangeError("No bin found!!"); + return bin(ret); } @@ -473,103 +408,54 @@ /// /// Looks through all the bins to see which one contains the point of /// interest. - const int getBinIndex(double coordX, double coordY) const { - // In case we are just operating on a regular grid - if (isGrid()) { - coordX += coordX/2000000000; - coordY += coordY/2000000000; - size_t indexY = (*_binHashSparse.first._cache.lower_bound(approx(coordY))).second; - - if (indexY < _binHashSparse.first.size()) { - foreach(Edge edgeY, _binHashSparse.first[indexY].second) { - if (edgeY.second.first < coordX && edgeY.second.second > coordX) { - size_t indexX = (*_binHashSparse.second._cache.lower_bound(approx(coordX))).second; - if (indexX < _binHashSparse.second.size()) { - foreach (Edge edgeX, _binHashSparse.second[indexX].second) { - if (edgeX.second.first < coordY && edgeX.second.second > coordY && - (edgeX.first == edgeY.first)) - return edgeX.first; - } - } - } - } - } - return -1; - } - - // In case we have something more complicated - for (size_t i = 0; i < _bins.size(); ++i) { - if (_bins[i].xMin() <= coordX && _bins[i].xMax() >= coordX && - _bins[i].yMin() <= coordY && _bins[i].yMax() >= coordY) - return i; - } - return -1; - } - - - /// Fast column number searcher - const size_t getBinColumn(size_t index) const { - // Check if assumptions are reasonable - if (!_isGrid) throw GridError("This operation can only be performed when an array is a grid!"); - if (index >= _bins.size()) throw RangeError("Index is bigger than the size of bins vector!"); - - // Find the column number - size_t ret = (*_binHashSparse.first._cache.lower_bound(approx(bin(index).yMin()))).second; - return ret; - } - - - /// Fast row number searcher - const size_t getBinRow(size_t index) const { - // Check if assumptions are reasonable - if (!_isGrid) throw GridError("This operation can only be performed when an array is a grid!"); - if (index >= _bins.size()) throw RangeError("Index is bigger than the size of bins vector!"); - - // Find the row number - size_t ret = (*_binHashSparse.second._cache.lower_bound(approx(bin(index).xMin()))).second; - return ret; + const long getBinIndex(double coordX, double coordY) const { + // First check that we are within the axis bounds at all + if (coordX < lowEdgeX() || coordX > highEdgeX()) return -1; + if (coordY < lowEdgeY() || coordY > highEdgeY()) return -1; + // Then return the lower-edge lookup (in both directions) from the hash map. + // NB. both upper_bound and lower_bound return values *greater* than (or equal) to coord, + // so we have to step back one iteration to get to the lower-or-equal containing bin edge. + BinHash::const_iterator itaboveX = _binhash.upper_bound(coordX); + SubBinHash::const_iterator itaboveY = (--itaboveX)->second.upper_bound(coordY); + int index = (--itaboveY)->second; + return index; } - /// Check if the axis has a grid structure or not - bool isGrid() const { - return _isGrid; - } + // /// Fast column number searcher + // const size_t getBinColumn(size_t index) const { + // // Check if assumptions are reasonable + // if (!_isGrid) throw GridError("This operation can only be performed when an array is a grid!"); + // if (index >= _bins.size()) throw RangeError("Index is bigger than the size of bins vector!"); + + // // Find the column number + // size_t ret = (*_binHashSparse.first._cache.lower_bound(approx(bin(index).yMin()))).second; + // return ret; + // } + + + // /// Fast row number searcher + // const size_t getBinRow(size_t index) const { + // // Check if assumptions are reasonable + // if (!_isGrid) throw GridError("This operation can only be performed when an array is a grid!"); + // if (index >= _bins.size()) throw RangeError("Index is bigger than the size of bins vector!"); + + // // Find the row number + // size_t ret = (*_binHashSparse.second._cache.lower_bound(approx(bin(index).xMin()))).second; + // return ret; + // } /// @brief Bin eraser /// - /// Removes a bin at a position. Additionally, modifies bin cache to - /// make it represent the new bin set. + /// Removes a bin at a position. void eraseBin(size_t index) { // Check the correctness of assumptions - if (index >= _bins.size()) throw RangeError("Index is bigger than the size of bins vector!"); - - _bins.erase(_bins.begin() + index); - // Check if delimiter if recomputed after every for run. - for (size_t i = 0; i < _binHashSparse.first.size(); ++i) { - for (size_t j = 0; j < _binHashSparse.first[i].second.size(); ++j) { - if (_binHashSparse.first[i].second[j].first == index) { - _binHashSparse.first[i].second.erase(_binHashSparse.first[i].second.begin() + j); - j--; - } - else if (_binHashSparse.first[i].second[j].first > index) { - _binHashSparse.first[i].second[j].first--; - } - } - } + if (index >= numBins()) throw RangeError("Index is bigger than the size of bins vector!"); - for (size_t i = 0; i < _binHashSparse.second.size(); ++i) { - for (size_t j = 0; j < _binHashSparse.second[i].second.size(); ++j) { - if (_binHashSparse.second[i].second[j].first == index) { - _binHashSparse.second[i].second.erase(_binHashSparse.second[i].second.begin() + j); - j--; - } - else if (_binHashSparse.second[i].second[j].first > index) { - _binHashSparse.second[i].second[j].first--; - } - } - } + /// @todo Check for overlaps + /// @todo If within the current bounds, create and rehash + /// @todo If outside the bounds, check for grid compatibility, create and rehash } //@} @@ -582,52 +468,35 @@ /// Scales the axis with a given scale. /// @todo Add a specific check for a scaling of 1.0, to avoid doing work when no scaling is wanted. void scaleXY(double scaleX, double scaleY) { - // Two loops are put on purpose, just to protect - // against improper _binHashSparse - for (size_t i = 0; i < _binHashSparse.first.size(); ++i) { - _binHashSparse.first[i].first *= scaleY; - for (size_t j = 0; j < _binHashSparse.first[i].second.size(); ++j) { - _binHashSparse.first[i].second[j].second.first *= scaleX; - _binHashSparse.first[i].second[j].second.second *= scaleX; - } - } - for (size_t i = 0; i < _binHashSparse.second.size(); ++i) { - _binHashSparse.second[i].first *= scaleX; - for (size_t j = 0; j < _binHashSparse.second[i].second.size(); ++j) { - _binHashSparse.second[i].second[j].second.first *= scaleY; - _binHashSparse.second[i].second[j].second.second *= scaleY; - } - } - - /// Regenerate the bin edges cache. - _binHashSparse.first.regenCache(); - _binHashSparse.second.regenCache(); - - /// Now, as we have the map rescaled, we need to update the bins foreach(Bin bin, _bins) { bin.scaleXY(scaleX, scaleY); } - _dbn.scaleXY(scaleX, scaleY); - for (size_t i = 0; i < _outflows.size(); ++i) { - for (size_t j =0; j < _outflows[i].size(); ++j) { - _outflows[i][j].scaleXY(scaleX, scaleY); - } - } + + /// @todo Outflows + // for (size_t i = 0; i < _outflows.size(); ++i) { + // for (size_t j =0; j < _outflows[i].size(); ++j) { + // _outflows[i][j].scaleXY(scaleX, scaleY); + // } + // } + + /// @todo Rehash } /// Scales the bin weights void scaleW(double scalefactor) { - _dbn.scaleW(scalefactor); - for (size_t i = 0; i < _outflows.size(); ++i) { - for (size_t j = 0; j < _outflows[i].size(); ++j) { - _outflows[i][j].scaleW(scalefactor); - } - } foreach(Bin bin, _bins) { bin.scaleW(scalefactor); } + _dbn.scaleW(scalefactor); + + /// @todo Outflows + // for (size_t i = 0; i < _outflows.size(); ++i) { + // for (size_t j = 0; j < _outflows[i].size(); ++j) { + // _outflows[i][j].scaleW(scalefactor); + // } + // } } //@} @@ -636,19 +505,10 @@ /// @name Operators //@{ - /// Equality operator + /// Equality operator (on binning only) bool operator == (const Axis2D& other) const { - if (isGrid()) { - foreach(Bin bin, _bins) { - int index = other.getBinIndex(bin.midpoint().first, bin.midpoint().second); - if (index != -1) { - if (other.bin(index) != bin) return false; - } - else return false; - } - return true; - } - else return _binHashSparse == other._binHashSparse; + /// @todo TODO + return true; } @@ -663,7 +523,7 @@ /// @todo Compatible but not equal binning to come soon. Axis2D<BIN2D, DBN>& operator += (const Axis2D<BIN2D, DBN>& toAdd) { if (*this != toAdd) { - throw LogicError("YODA::Histo1D: Cannot add axes with different binnings."); + throw LogicError("YODA::Axis2D: Cannot add axes with different binnings."); } for (size_t i = 0; i < bins().size(); ++i) { bin(i) += toAdd.bin(i); @@ -679,7 +539,7 @@ /// @todo Compatible but not equal binning to come soon. Axis2D<BIN2D, DBN>& operator -= (const Axis2D<BIN2D, DBN>& toSubtract) { if (*this != toSubtract) { - throw LogicError("YODA::Histo1D: Cannot add axes with different binnings."); + throw LogicError("YODA::Axis2D: Cannot add axes with different binnings."); } for (size_t i = 0; i < bins().size(); ++i) { bin(i) -= toSubtract.bin(i); @@ -693,456 +553,105 @@ private: - int _hasAbove(size_t index){ - if(index == _bins.size() - 1) return -1; - if(fuzzyEquals(_bins[index].yMax(), _bins[index+1].yMin()) && - fuzzyEquals(_bins[index].xMin(), _bins[index+1].xMin()) && - fuzzyEquals(_bins[index].xMax(), _bins[index+1].xMax())) return 1; - if(fuzzyEquals(_bins[index].xMax(), _bins[index+1].xMin())) return 0; - return 1500; - } + // /// Add new bins, constructed from two sorted vectors of edges, to the axis + // void _addBins(const std::vector<double>& xbinedges, const std::vector<double>& ybinedges) { + // //std::sort(binedges.begin(), binedges.end()); + // if (_edgeInRange(binedges.front(), binedges.back())) { + // throw RangeError("New bin range overlaps with existing bin edges"); + // } + // for (size_t i = 0; i < binedges.size() - 1; ++i) { + // _bins.push_back(BIN1D(binedges[i], binedges[i+1])); + // } + // _updateAxis(); + // } - /// @brief Outflows pre-setter - /// Sets the correct number of bins in each of the outflows. - void _setOutflows() { - _outflows.resize(8); + /// Add new bins to the axis + void _addBins(const Bins& bins) { + for (size_t i = 0; i < bins.size(); ++i) { - _outflows[0].resize(1); - _outflows[1].resize(_binHashSparse.second.size()); - _outflows[2].resize(1); - _outflows[3].resize(_binHashSparse.first.size()); - _outflows[4].resize(1); - _outflows[5].resize(_binHashSparse.second.size()); - _outflows[6].resize(1); - _outflows[7].resize(_binHashSparse.first.size()); + /// @todo Check for 2D edge overlaps - } - - - /// 2D Outflow filler - /// The function checks which outflow the coordinates are in - /// and fills the right one. - void _fillOutflows(double x, double y, double weight) { - if (x < _lowEdgeX && y > _highEdgeY) _outflows[0][0].fill(x, y, weight); - else if (x > _lowEdgeX && x < _highEdgeX && y > _highEdgeY) - { - size_t element = _binaryS(_binHashSparse.second, x, 0, _binHashSparse.second.size()); - _outflows[1][element].fill(x, y, weight); - } - else if (x > _highEdgeX && y > _highEdgeY) _outflows[2][0].fill(x, y, weight); - else if (x > _highEdgeX && y > _lowEdgeY && y < _highEdgeY) - { - size_t element = _binaryS(_binHashSparse.first, y, 0, _binHashSparse.first.size()); - _outflows[3][element].fill(x, y, weight); - } - else if (x > _highEdgeX && y < _lowEdgeY) _outflows[4][0].fill(x, y, weight); - else if (x > _lowEdgeX && x < _highEdgeX && y < _lowEdgeY) - { - size_t element = _binaryS(_binHashSparse.second, x, 0, _binHashSparse.second.size()); - _outflows[5][element].fill(x, y, weight); - } - else if (x < _lowEdgeX && y < _lowEdgeY) _outflows[6][0].fill(x, y, weight); - else if (x < _lowEdgeX && y > _lowEdgeY && y < _highEdgeY) - { - size_t element = _binaryS(_binHashSparse.first, y, 0, _binHashSparse.first.size()); - _outflows[7][element].fill(x, y, weight); - } - - } - - /// 3D outflow filler - void _fillOutflows(double x, double y, double z, double weight) { - if (x < _lowEdgeX && y > _highEdgeY) _outflows[0][0].fill(x, y, z, weight); - else if (x > _lowEdgeX && x < _highEdgeX && y > _highEdgeY) - { - size_t element = _binaryS(_binHashSparse.second, x, 0, _binHashSparse.second.size()); - _outflows[1][element].fill(x, y, z, weight); - } - else if (x > _highEdgeX && y > _highEdgeY) _outflows[2][0].fill(x, y, z, weight); - else if (x > _highEdgeX && y > _lowEdgeY && y < _highEdgeY) - { - size_t element = _binaryS(_binHashSparse.first, y, 0, _binHashSparse.first.size()); - _outflows[3][element].fill(x, y, z, weight); - } - else if (x > _highEdgeX && y < _lowEdgeY) _outflows[4][0].fill(x, y, z, weight); - else if (x > _lowEdgeX && x < _highEdgeX && y < _lowEdgeY) - { - size_t element = _binaryS(_binHashSparse.second, x, 0, _binHashSparse.second.size()); - _outflows[5][element].fill(x, y, z, weight); - } - else if (x < _lowEdgeX && y < _lowEdgeY) _outflows[6][0].fill(x, y, z, weight); - else if (x < _lowEdgeX && y > _lowEdgeY && y < _highEdgeY) - { - size_t element = _binaryS(_binHashSparse.first, y, 0, _binHashSparse.first.size()); - _outflows[7][element].fill(x, y, z, weight); - } - - } - - /// @brief Checks if our bins form a grid. - /// - /// This function uses a neat property of _binHashSparse. If it is - /// containing a set of edges forming a grid without gaps in the middle it - /// will have the same number of edges in the inner subcaches and half of - /// this amount in the outer (grid boundary) subcaches. This makes isGrid() - /// a very, very fast function. - void _genGridCache() { - // Check if the number of edges parallel to the x axis is proper in every - // subcache. - size_t sizeX = _binHashSparse.first[0].second.size(); - for (size_t i = 1; i < _binHashSparse.first.size(); ++i) { - if (i == _binHashSparse.first.size() - 1) { - if (_binHashSparse.first[i].second.size() != sizeX) { - _isGrid = false; - return; - } - } - else if (_binHashSparse.first[i].second.size() != 2*sizeX) { - _isGrid = false; - return; - } - } - - // Do the same for edges parallel to the y axis. - size_t sizeY = _binHashSparse.second[0].second.size(); - for (size_t i = 1; i < _binHashSparse.second.size(); ++i) { - if (i != _binHashSparse.second.size() - 1) { - if (2*sizeY != _binHashSparse.second[i].second.size()) { - _isGrid = false; - return; - } - } - else if (_binHashSparse.second[i].second.size() != sizeY) { - _isGrid = false; - return; - } + // if (_edgeInRange(bins[i].xMin(), bins[i].xMax())) { + // throw RangeError("New bin range overlaps with existing bin edges"); + // } + _bins.push_back(bins[i]); } - - // If everything is proper, announce it. - _isGrid = true; + _updateAxis(); } - /// @brief Segment validator function + /// Sort the bins vector, and regenerate the bin hash /// - /// This a 'dispatcher' function. It checks if the segment in question - /// is vertical or horizontal and launches the appropriate function - /// searching for cuts in the prope direction. Since it operates on - /// a vector of segments it is prepared to act on arbitrarly large sets of edges, - /// in practice usually being four sides of a rectangular bin. - /// - /// Notice that it will never be checked, in the current state, if there is a cut - /// in edges in the edgeset. This imposes the requirement of provide the program - /// with non-degenerate bins, until checking in implemented. However, it doesn't seem - /// to be needed, as edges are not generated by a user. - /// - /// This is also a perfect place to parallelize, if required. - bool _validateEdge(std::vector<Segment>& edges) { - // Setting the return variable. True means that no cuts were detected. - bool ret = true; - - // Looping over all the edges provided - foreach(Segment edge, edges) { - // If the X coordinate of the starting point is the same - // as X coordinate of the ending one, checks if there are cuts - // on this vertical segment. - if (fuzzyEquals(edge.first.first, edge.second.first)) { - ret = _findCutsY(edge); - } - - /// Check if the segment is horizontal and is it cutting any bin that already exists - else if (fuzzyEquals(edge.first.second, edge.second.second)) { - ret = _findCutsX(edge); - } - - // This is a check that discards the bin if it is not a rectangle - // composed of vertical and horizontal segments. - else { - ret = false; + /// The bin hash is purely for searching, and is generated from the bins list only. + void _updateAxis() { + std::sort(_bins.begin(), _bins.end()); + _binhash.clear(); + for (size_t i = 0; i < numBins(); ++i) { + // Add low edge hash for each bin + _binhash[bin(i).xMin()] = i; + // If the next bin is not contiguous, add a gap index for the high edge of this bin + if (i+1 < numBins() && !fuzzyEquals(bin(i).xMax(), bin(i+1).xMin())) { + _binhash[bin(i).xMax()] = -1; } - - // If a cut was detected, return false immediately. - if (!ret) return false; } - // If no cuts were detected in any of the edges, tell the launching function about this - return true; } - /// @brief A binary search function - /// - /// This is conceptually the same implementation as in STL - /// but because it returns the index of an element in a vector, - /// it is easier to use in our case than the STL implementation - /// that returns a pointer at the element. - /// - /// @todo This is far too big to be inline: move it to the bottom of this file, or perhaps to a .cc - /// @todo Does this actually have to be a member function? Isn't it just a function? - size_t _binaryS(Utils::cachedvector<EdgeCollection>& toSearch, - double value, size_t lower, size_t higher) { - // Just a check if such degenerate situation happens - if (lower == higher) return lower; - - // Choose a midpoint that will be our pivot - size_t where = (higher+lower)/2; - - // Launch the same procedure on half of the range above the pivot - if (value >= toSearch[where].first) { - if (where == toSearch.size() - 1) return where; - if (value <= toSearch[where+1].first) return where; - return _binaryS(toSearch, value, where, higher); - } - - // This is not a redundant check, because of the nature of int division. - if (where == 0) return where; - - // Check if the value is somewhere in-between an element at the position - // in question and an element at a lower position. If so, return an index - // to the current positon. - if (value >= toSearch[where-1].first) return where; - - // If none of the above occurs, the value must be smaller that the element - // at the current position. In such case, launch the search on half of the - // interval below the current position. - return _binaryS(toSearch, value, lower, where); - } + /// @todo Convert from 1D to 2D + // /// Check if there are any bin edges between values @a from and @a to. + // bool _edgeInRange(double from, double to) const { + // return (--_binhash.upper_bound(from)) != (--_binhash.lower_bound(to)); + // } - /// @brief Function that finds cuts of horizontal edges. - /// - /// A specialised function that tries to exploit the fact - /// that edges can cut one another only on right angles - /// to the highest extent. The inner workings are explained - /// in the comments placed in the function body. - /// - /// @todo Explain what "cuts" are -- this is not obvious - bool _findCutsX(Segment& edge) { - // Look up the limits of search in the _binHashSparse - // structure. We are not interested in the vertical edges - // that are before the beginning of our segment or after its end. - size_t i = _binaryS(_binHashSparse.second, edge.first.first, 0, _binHashSparse.second.size()); - size_t end = _binaryS(_binHashSparse.second, edge.second.first, 0, _binHashSparse.second.size()); - - for (; i < end; ++i) { - // Scroll through all the vertical segments with a given X coordinate - // and see if any of those fulfills the cutting requirement. If it does, - // announce it. - for (size_t j = 0; j < _binHashSparse.second[i].second.size(); ++j) { - // Note that we are not taking into account the edges touching the - // segment in question. That's because sides of a bin touch - if (_binHashSparse.second[i].second[j].second.first < edge.first.second && - _binHashSparse.second[i].second[j].second.second > edge.first.second && - !fuzzyEquals(_binHashSparse.second[i].second[j].second.first, edge.first.second) && - !fuzzyEquals(_binHashSparse.second[i].second[j].second.second, edge.first.second)) { - return false; - } - } - } - // If none of the existing edges is cutting this edge, announce it - return true; - } + /// @todo Convert from 1D to 2D + // /// Check if there are any gaps in the axis' binning between bin indices @a from and @a to, inclusive. + // bool _gapInRange(size_t ifrom, size_t ito) const { + // assert(ifrom < numBins() && ito < numBins() && ifrom <= ito); + // if (ifrom == ito) return false; + // BinHash::const_iterator start = (--_binhash.upper_bound(bin(ifrom).midpoint())); + // BinHash::const_iterator end = _binhash.upper_bound(bin(ifrom).midpoint()); + // for (BinHash::const_iterator it = start; it != end; ++it) { + // if (it->second == -1) return true; + // } + // return false; + // } - /// @brief Function that finds cuts of vertical edges - /// - /// For a detailed description, see the documentation for _findCutsX(). - /// - /// @todo Explain what "cuts" are -- this is not obvious - /// @todo Can the code for "cut" finding be abstracted to work in both - /// directions, to avoid writing (and maintaining) it twice? - bool _findCutsY(Segment& edge) { - size_t i = _binaryS(_binHashSparse.first, edge.first.second, 0, _binHashSparse.first.size()); - size_t end = _binaryS(_binHashSparse.first, edge.second.second, 0, _binHashSparse.first.size()); - for (; i < end; ++i) { - for (size_t j = 0; j < _binHashSparse.first[i].second.size(); ++j) { - if (_binHashSparse.first[i].second[j].second.first < edge.first.first && - _binHashSparse.first[i].second[j].second.second > edge.first.first && - !fuzzyEquals(_binHashSparse.first[i].second[j].second.first, edge.first.first) && - !fuzzyEquals(_binHashSparse.first[i].second[j].second.second, edge.first.first)) { - return false; - } - } - } - return true; - } - - - /// @brief Bin inserter - /// - /// It contains all the commands that need to executed to properly add a - /// bin. Specifically edges are added to the edge cache (_binHashSparse) and - /// a bin is created from those edges. - void _addEdge(Segment edges, std::pair<Utils::cachedvector<EdgeCollection>, - Utils::cachedvector<EdgeCollection> >& binHash, bool addBin = true) { - - // This is the part in charge of adding each of the segments - // to the edge cache. Segments are assumed to be validated - // beforehand. - foreach(Segment edge, edges) { - // Do the following if the edge is vertical. - // Those two cases need to be distinguished - // because of the way in which edge cache is structured. - if (edge.first.first == edge.second.first) { - // See if our edge has the same X coordinate as any other - // edge that is currently in the cache. - - // Keeps the status of the search - bool found = false; - - // There is only a certain set of X coordinates that we need to sweep - // to check if our segment has the same X coordinate. Find them. - size_t i = _binaryS(binHash.second, edge.first.first, 0, binHash.second.size()) - 1; - if (i < 0) i = 0; - size_t end = i + 3; - - // For the coordinates in range, check if one of them is an X - // coordinate of the segment. - for (; i < binHash.second.size() && i < end ; ++i) { - /// If this is the case, do what is needed to be done. - if (fuzzyEquals(binHash.second[i].first, edge.first.first)) { - binHash.second[i].second.push_back(std::make_pair(_bins.size(), - std::make_pair(edge.first.second, edge.second.second))); - found = true; - break; - } - } - - // If no edge with the same X coordinate exist, create - // a new subhash at the X coordinate of a segment. - if (!found) { - std::vector<Edge> temp; - temp.push_back(std::make_pair(_bins.size(), std::make_pair(edge.first.second, edge.second.second))); - binHash.second.push_back(std::make_pair(edge.first.first, temp)); - sort(binHash.second.begin(), binHash.second.end()); - } - } - - // See the vertical case for description of a horizontal one - else if (edge.first.second == edge.second.second) { - bool found = false; - size_t i = _binaryS(binHash.first, edge.first.second, 0, binHash.first.size())-1; - if (i < 0) i = 0; - size_t end = i+3; - for (; i < binHash.first.size() && i < end; ++i) { - if (fuzzyEquals(binHash.first[i].first, edge.first.second)) { - binHash.first[i].second.push_back(std::make_pair(_bins.size(), - std::make_pair(edge.first.first, edge.second.first))); - found = true; - } - } - if (!found) { - std::vector<Edge> temp; - temp.push_back(std::make_pair(_bins.size(), std::make_pair(edge.first.first, edge.second.first))); - binHash.first.push_back(std::make_pair(edge.second.second, temp)); - sort(binHash.first.begin(), binHash.first.end()); - } - } - } - - // Now, create a bin with the edges provided - if (addBin) _bins.push_back(BIN2D(edges)); - } - - - /// @brief Orientation fixer - /// - /// Check if the orientation of an edge is proper - /// for the rest of the algorithm to work on, and if it is not - /// fix it. - void _fixOrientation(Segment& edge) { - if (fuzzyEquals(edge.first.first, edge.second.first)) { - if (edge.first.second > edge.second.second) { - double temp = edge.second.second; - edge.second.second = edge.first.second; - edge.first.second = temp; - } - } - else if (edge.first.first > edge.second.first) { - double temp = edge.first.first; - edge.first.first = edge.second.first; - edge.second.first = temp; - } - } - - - /// @brief Axis creator - /// - /// The top-level function taking part in the process of adding - /// edges. Creating an axis is the same operation for it as adding new bins - /// so it can be as well used to add some custom bins. - /// - /// It accepts two extremal points of a rectangle (top-right and - /// bottom-left) as input. - void _mkAxis(const std::vector<Segment>& binLimits) { - - // For each of the rectangles - foreach(Segment binLimit, binLimits) { - // Produce the segments that a rectangle is composed of - Segment edge1 = - std::make_pair(binLimit.first, - std::make_pair(binLimit.first.first, binLimit.second.second)); - Segment edge2 = - std::make_pair(std::make_pair(binLimit.first.first, binLimit.second.second), - binLimit.second); - Segment edge3 = - std::make_pair(std::make_pair(binLimit.second.first, binLimit.first.second), - binLimit.second); - Segment edge4 = - std::make_pair(binLimit.first, - std::make_pair(binLimit.second.first, binLimit.first.second)); - - // Check if they are made properly - _fixOrientation(edge1); _fixOrientation(edge2); - _fixOrientation(edge3); _fixOrientation(edge4); - - // Add all the segments to a vector - std::vector<Segment> edges; - edges.push_back(edge1); edges.push_back(edge2); - edges.push_back(edge3); edges.push_back(edge4); - - // And check if a bin is a proper one, if it is, add it. - if (_validateEdge(edges)) _addEdge(edges, _binHashSparse); - } - - // Setting all the caches - _binHashSparse.first.regenCache(); - _binHashSparse.second.regenCache(); - _genGridCache(); + /// 2D outflow filler + /// The function checks which outflow the coordinates are in + /// and fills the right one. + void _fillOutflows(double x, double y, double weight) { + /// @todo TODO } private: + /// @name Data structures + //@{ + /// Bins contained in this histogram Bins _bins; - /// Outflow distributions - /// It contains eight subvectors, each being 1/8 of an outflow - /// and numbered clockwise from top left corner. The 'corner' outflows - /// contain just one DBN each. The ones between them contain as many DBNs - /// as the number of columns/rows in the respective part of the grid. - std::vector<std::vector<DBN> > _outflows; - /// Total distribution DBN _dbn; - /// @brief Bin hash structure + /// Outflow distributions /// - /// First in pair is holding the horizontal edges indexed by first.first - /// which is an y coordinate. The last pair specifies x coordinates (begin, end) of - /// the horizontal edge. - /// Analogous for the second member of the pair. + /// This contains eight subvectors, each being 1/8 of an outflow + /// and numbered clockwise from top left corner. The 'corner' outflows + /// contain just one DBN each. The ones between them contain as many DBNs + /// as the number of columns/rows in the respective part of the grid. /// - /// For the fullest description, see typedefs at the beginning - /// of this file. - std::pair<Utils::cachedvector<EdgeCollection>, Utils::cachedvector<EdgeCollection> > _binHashSparse; + /// @todo Replace with a more specialised class or a fixed array? + std::vector<std::vector<DBN> > _outflows; - /// Low/high edges - double _highEdgeX, _highEdgeY, _lowEdgeX, _lowEdgeY; + /// Cached bin edges for searching + BinHash _binhash; - /// Flag to mark if this histogram has a grid structure or not - bool _isGrid; + //@} }; @@ -1166,7 +675,7 @@ tmp -= second; return tmp; } - + //@} Modified: trunk/include/YODA/Bin1D.h ============================================================================== --- trunk/include/YODA/Bin1D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/Bin1D.h Fri Jun 15 19:25:00 2012 (r470) @@ -33,30 +33,35 @@ /// @name Constructors //@{ - /// Init a new, empty bin with a pair of edges. - Bin1D(double lowedge, double highedge) - : _edges( std::make_pair(lowedge, highedge) ) - { - assert( _edges.second > _edges.first ); - } + // /// Make a new, empty bin with a pair of edges. + // Bin1D(double lowedge, double highedge) + // : _edges( std::make_pair(lowedge, highedge) ) + // { + // if (_edges.second < _edges.first) { + // throw RangeError("The bin edges are wrongly defined!"); + // } + // } - /// Init a new, empty bin with a pair of edges. + /// Make a new, empty bin with a pair of edges. Bin1D(const std::pair<double,double>& edges) - : _edges( edges ) + : _edges(edges) { - assert( _edges.second >= _edges.first ); + if (_edges.second < _edges.first) { + throw RangeError("The bin edges are wrongly defined!"); + } } - /// @brief Init a bin with all the components of a fill history. + /// @brief Make a bin with all the components of a fill history. /// /// Mainly intended for internal persistency use. - Bin1D(double lowedge, double highedge, const DBN& dbn) - : _edges( std::make_pair(lowedge, highedge) ), - _dbn(dbn) + Bin1D(const std::pair<double,double>& edges, const DBN& dbn) + : _edges(edges), _dbn(dbn) { - assert( _edges.second >= _edges.first ); + if (_edges.second < _edges.first) { + throw RangeError("The bin edges are wrongly defined!"); + } } Modified: trunk/include/YODA/Bin2D.h ============================================================================== --- trunk/include/YODA/Bin2D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/Bin2D.h Fri Jun 15 19:25:00 2012 (r470) @@ -27,40 +27,64 @@ class Bin2D : public Bin { public: - /// Convenience typedefs - typedef typename std::pair<double, double> Point; - typedef typename std::pair<Point, Point> Segment; - /// @name Constructors //@{ - /// Init a new, empty bin with a pair of edges. - Bin2D(double xMin, double yMin, double xMax, double yMax) { - if (xMin > xMax || yMin > yMax) { - throw RangeError("The bins are wrongly defined!"); + // /// Make a new, empty bin with two pairs of edges. + // Bin2D(double xmin, double ymin, double xmax, double ymax) + // : _xedges( std::make_pair(xmin, xmax) ), + // _yedges( std::make_pair(ymin, ymax) ) + // { + // if (_xedges.second < _xedges.first) { + // throw RangeError("The bin x-edges are wrongly defined!"); + // } + // if (_yedges.second < _yedges.first) { + // throw RangeError("The bin y-edges are wrongly defined!"); + // } + // } + + + /// Make a new, empty bin with two pairs of edges. + Bin2D(const std::pair<double, double>& xedges, const std::pair<double, double>& yedges) + : _xedges( xedges ), _yedges( yedges ) + { + if (_xedges.second < _xedges.first) { + throw RangeError("The bin x-edges are wrongly defined!"); + } + if (_yedges.second < _yedges.first) { + throw RangeError("The bin y-edges are wrongly defined!"); } - _edges.first.first = xMin; - _edges.first.second = yMin; - _edges.second.first = xMax; - _edges.second.second = yMax; } - /// Init a new, empty bin with a pair of edges. - Bin2D(const Segment& edges) { - _edges = edges; + /// @brief Make a bin with all the components of a fill history. + /// + /// Mainly intended for internal persistency use. + Bin2D(const std::pair<double, double>& xedges, + const std::pair<double, double>& yedges, const DBN& dbn) + : _xedges(xedges), _yedges(yedges), _dbn(dbn) + { + if (_xedges.second < _xedges.first) { + throw RangeError("The bin x-edges are wrongly defined!"); + } + if (_yedges.second < _yedges.first) { + throw RangeError("The bin y-edges are wrongly defined!"); + } } + /// Copy constructor Bin2D(const Bin2D<DBN>& b) - : _edges(b._edges), + : _xedges(b._xedges), + _yedges(b._yedges), _dbn(b._dbn) { } /// Copy assignment Bin2D<DBN>& operator = (const Bin2D<DBN>& b) { - _edges = b._edges; + _xedges = b._xedges; + _yedges = b._yedges; _dbn = b._dbn; return *this; } @@ -83,11 +107,11 @@ /// Scale the x and y coordinates and distributions. void scaleXY(double scaleX, double scaleY) { - _edges.first.first *= scaleX; - _edges.second.first *= scaleX; + _xedges.first *= scaleX; + _xedges.second *= scaleX; - _edges.first.second *= scaleY; - _edges.second.second *= scaleY; + _yedges.first *= scaleY; + _yedges.second *= scaleY; _dbn.scaleXY(scaleX, scaleY); } @@ -102,7 +126,7 @@ /// Lower x limit of the bin (inclusive). double lowEdgeX() const { - return _edges.first.first; + return _xedges.first; } /// Synonym for lowEdgeX() double xMin() const { @@ -111,7 +135,7 @@ /// Lower y limit of the bin (inclusive). double lowEdgeY() const { - return _edges.first.second; + return _yedges.first; } /// Synonym for lowEdgeY() double yMin() const { @@ -120,7 +144,7 @@ /// Upper x limit of the bin (exclusive). double highEdgeX() const { - return _edges.second.first; + return _xedges.second; } /// Synonym for highEdgeX() double xMax() const { @@ -129,18 +153,13 @@ /// Upper y limit of the bin (exclusive). double highEdgeY() const { - return _edges.second.second; + return _yedges.second; } /// Synonym for highEdgeY() double yMax() const { return highEdgeY(); } - /// Get the {low,high} edges as an STL @c pair. - const Segment edges() const { - return _edges; - } - /// Width of the bin in x double widthX() const { return xMax() - xMin(); @@ -152,7 +171,7 @@ } /// The mean position in the bin, or the midpoint if that is not available. - Point focus() const { + std::pair<double, double> focus() const { if (!isZero(sumW())) { return std::make_pair(xMean(), yMean()); } else { @@ -161,7 +180,7 @@ } /// Geometric centre of the bin, i.e. high+low/2.0 - Point midpoint() const { + std::pair<double, double> midpoint() const { return std::make_pair((xMax() + xMin())/2, (yMax() + yMin())/2); } @@ -309,7 +328,7 @@ /// This operator is defined for adding two bins with equivalent binning. /// It cannot be used to merge two bins into one larger bin. Bin2D<DBN>& add(const Bin2D<DBN>& b) { - if (_edges != b._edges) { + if (_xedges != b._xedges || _yedges != b._yedges) { throw LogicError("Attempted to add two bins with different edges"); } _dbn += b._dbn; @@ -322,7 +341,7 @@ /// This operator is defined for subtracting two bins with equivalent binning. /// It cannot be used to merge two bins into one larger bin. Bin2D<DBN>& subtract(const Bin2D<DBN>& b) { - if (_edges != b._edges) { + if (_xedges != b._xedges || _yedges != b._yedges) { throw LogicError("Attempted to add two bins with different edges"); } _dbn -= b._dbn; @@ -335,7 +354,8 @@ protected: /// The bin limits - Segment _edges; + std::pair<double,double> _xedges; + std::pair<double,double> _yedges; // Distribution of weighted x (and perhaps y) values DBN _dbn; Modified: trunk/include/YODA/Histo2D.h ============================================================================== --- trunk/include/YODA/Histo2D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/Histo2D.h Fri Jun 15 19:25:00 2012 (r470) @@ -50,16 +50,6 @@ _axis(nbinsX, lowerX, upperX, nbinsY, lowerY, upperY) { } - /// A default constructor. One needs to provide two points - /// (top-right and bottom-left) for each rectangular bin that - /// is created. It is assumed that the binedges vector is nonempty (why btw?). - /// @todo Drop the pairings -- it is more natural, less contrived, and cleaner in code as xlow/high and ylow/high - Histo2D(const std::vector<std::pair<std::pair<double,double>, std::pair<double,double> > >& binedges, - const std::string& path="", - const std::string& title="") - : AnalysisObject("Histo2D", path, title), - _axis(binedges) - { } /// Constructor accepting the bin edges on X and Y axis. Histo2D(const std::vector<double>& xedges, const std::vector<double>& yedges, @@ -68,6 +58,7 @@ _axis(xedges, yedges) { } + /// Copy constructor with optional new path Histo2D(const Histo2D& h, const std::string& path=""); @@ -92,13 +83,11 @@ /// @name Modifiers //@{ - /// @brief Fill histo by value and weight - /// - /// It relies on Axis2D for searching procedures and complains loudly if no - /// bin was found. - int fill(double x, double y, double weight=1.0); + /// @brief Fill histo with weight at (x,y) + void fill(double x, double y, double weight=1.0); /// @brief Reset the histogram. + /// /// Keep the binning but set all bin contents and related quantities to zero void reset() { _axis.reset(); @@ -128,20 +117,23 @@ _axis.scaleXY(scaleX, scaleY); } - /// Adding bins - void addBin(const std::vector<std::pair<std::pair<double,double>, std::pair<double,double> > > coords) { - _axis.addBin(coords); - } - - /// Adding bins which is not so eloquent - void addBin(double lowX, double lowY, double highX, double highY) { - _axis.addBin(lowX, lowY, highX, highY); - } - - /// Merge the bins - void mergeBins(size_t from, size_t to) { - _axis.mergeBins(from, to); - } + // /// Adding bins + /// @todo TODO + // void addBin(const std::vector<std::pair<std::pair<double,double>, std::pair<double,double> > > coords) { + // _axis.addBin(coords); + // } + + // /// Adding bins which is not so eloquent + /// @todo TODO + // void addBin(double lowX, double lowY, double highX, double highY) { + // _axis.addBin(lowX, lowY, highX, highY); + // } + + // /// Merge the bins + /// @todo TODO + // void mergeBins(size_t from, size_t to) { + // _axis.mergeBins(from, to); + // } void eraseBin(size_t index) { _axis.eraseBin(index); @@ -149,9 +141,10 @@ /// Rebin the whole histo by a @a factorX in the X direction and /// @a factorY in the Y direction - void rebin(size_t factorX, size_t factorY){ - _axis.rebin(factorX, factorY); - } + /// @todo TODO + // void rebin(size_t factorX, size_t factorY){ + // _axis.rebin(factorX, factorY); + // } //@} @@ -355,31 +348,31 @@ //@} - /// @name Slicing operators - //@{ - - /// @brief Create a Histo1D for the bin slice parallel to the x axis at the specified y coordinate - /// - /// Note that the created histogram will not have correctly filled underflow and overflow bins. - /// @todo It's not really *at* the specified y coord: it's for the corresponding bin row. - /// @todo Change the name! - Histo1D cutterX(double atY, const std::string& path="", const std::string& title=""); + // /// @name Slicing operators + // //@{ - - /// @brief Create a Histo1D for the bin slice parallel to the y axis at the specified x coordinate - /// - /// Note that the created histogram will not have correctly filled underflow and overflow bins. - /// @todo It's not really *at* the specified x coord: it's for the corresponding bin row. - /// @todo Change the name! - Histo1D cutterY(double atX, const std::string& path="", const std::string& title=""); - - - /// @brief X-wise Profile1D creator from Histo2D - Profile1D mkProfileX(); - - /// @brief Y-wise Profile1D creator from Histo2D - Profile1D mkProfileY(); - //@} + // /// @brief Create a Histo1D for the bin slice parallel to the x axis at the specified y coordinate + // /// + // /// Note that the created histogram will not have correctly filled underflow and overflow bins. + // /// @todo It's not really *at* the specified y coord: it's for the corresponding bin row. + // /// @todo Change the name! + // Histo1D cutterX(double atY, const std::string& path="", const std::string& title=""); + + + // /// @brief Create a Histo1D for the bin slice parallel to the y axis at the specified x coordinate + // /// + // /// Note that the created histogram will not have correctly filled underflow and overflow bins. + // /// @todo It's not really *at* the specified x coord: it's for the corresponding bin row. + // /// @todo Change the name! + // Histo1D cutterY(double atX, const std::string& path="", const std::string& title=""); + + + // /// @brief X-wise Profile1D creator from Histo2D + // Profile1D mkProfileX(); + + // /// @brief Y-wise Profile1D creator from Histo2D + // Profile1D mkProfileY(); + // //@} Modified: trunk/include/YODA/HistoBin1D.h ============================================================================== --- trunk/include/YODA/HistoBin1D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/HistoBin1D.h Fri Jun 15 19:25:00 2012 (r470) @@ -26,23 +26,23 @@ /// @name Constructor giving bin low and high edges. //@{ - /// Init a new, empty bin with a pair of edges. + /// Make a new, empty bin with a pair of edges. HistoBin1D(double lowedge, double highedge) - : Bin1D<Dbn1D>(lowedge, highedge) + : Bin1D<Dbn1D>(std::make_pair(lowedge, highedge)) { } - /// Init a new, empty bin with a pair of edges. + /// Make a new, empty bin with a pair of edges. HistoBin1D(const std::pair<double,double>& edges) : Bin1D<Dbn1D>(edges) { } - /// @brief Init a bin with all the components of a fill history. + /// @brief Make a bin with all the components of a fill history. /// /// Mainly intended for internal persistency use. - HistoBin1D(double lowedge, double highedge, const Dbn1D& dbnx) - : Bin1D<Dbn1D>(lowedge, highedge, dbnx) + HistoBin1D(std::pair<double, double> edges, const Dbn1D& dbnx) + : Bin1D<Dbn1D>(edges, dbnx) { } Modified: trunk/include/YODA/HistoBin2D.h ============================================================================== --- trunk/include/YODA/HistoBin2D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/HistoBin2D.h Fri Jun 15 19:25:00 2012 (r470) @@ -23,22 +23,28 @@ /// @name Constructors //@{ - /// Constructor accepting a set of extremal points of a bin - HistoBin2D(double xMin, double xMax, - double yMin, double yMax) - : Bin2D<Dbn2D>(xMin, yMin, xMax, yMax) + /// Make a new, empty bin with two pairs of edges. + HistoBin2D(double xmin, double ymin, double xmax, double ymax) + : Bin2D<Dbn2D>(std::make_pair(xmin, ymin), std::make_pair(xmax, ymax)) { } /// Constructor accepting a set of all edges of a bin - HistoBin2D(std::pair<std::pair<double,double>, std::pair<double,double> >& edges) - : Bin2D<Dbn2D>(edges) - { } - - - /// @todo Add copy constructor - - //@} - + HistoBin2D(const std::pair<double,double>& xedges, std::pair<double,double>& yedges) + : Bin2D<Dbn2D>(xedges, yedges) + { } + + /// @brief Make a bin with all the components of a fill history. + /// + /// Mainly intended for internal persistency use. + HistoBin2D(const std::pair<double, double>& xedges, + const std::pair<double, double>& yedges, const Dbn2D& dbn) + : Bin2D<Dbn2D>(xedges, yedges, dbn) + { } + + /// Copy constructor + HistoBin2D(const HistoBin2D& pb) + : Bin2D<Dbn2D>(pb) + { } /// @name Modifiers //@{ @@ -95,20 +101,20 @@ /// @name Transformers //@{ - /// @brief Transformer taking x as the primary axis of ProfileBin1D - /// @todo Need to think about the name, and clarify what "primary axis" means - ProfileBin1D transformX() { - ProfileBin1D ret(xMin(), xMax(), Dbn2D(_dbn)); - return ret; - } - - /// @brief Transformer taking y as the primary axis of ProfileBin1D - /// @todo Need to think about the name, and clarify what "primary axis" means - ProfileBin1D transformY() { - Dbn2D dbn = _dbn; dbn.flipXY(); - ProfileBin1D ret(yMin(), yMax(), Dbn2D(dbn)); - return ret; - } + // /// @brief Transformer taking x as the primary axis of ProfileBin1D + // /// @todo Need to think about the name, and clarify what "primary axis" means + // ProfileBin1D transformX() { + // ProfileBin1D ret(std::make_pair(xMin(), xMax()), Dbn2D(_dbn)); + // return ret; + // } + + // /// @brief Transformer taking y as the primary axis of ProfileBin1D + // /// @todo Need to think about the name, and clarify what "primary axis" means + // ProfileBin1D transformY() { + // Dbn2D dbn = _dbn; dbn.flipXY(); + // ProfileBin1D ret(std::make_pair(yMin(), yMax()), Dbn2D(dbn)); + // return ret; + // } //@} }; Modified: trunk/include/YODA/ProfileBin1D.h ============================================================================== --- trunk/include/YODA/ProfileBin1D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/ProfileBin1D.h Fri Jun 15 19:25:00 2012 (r470) @@ -28,7 +28,7 @@ /// Constructor giving bin low and high edges. ProfileBin1D(double lowedge, double highedge) - : Bin1D<Dbn2D>(lowedge, highedge) + : Bin1D<Dbn2D>(std::make_pair(lowedge, highedge)) { } @@ -38,11 +38,11 @@ { } - /// @brief Init a profile bin with all the components of a fill history. + /// @brief Make a profile bin with all the components of a fill history. /// /// Mainly intended for internal persistency use. - ProfileBin1D(double lowedge, double highedge, const Dbn2D& dbnxy) - : Bin1D<Dbn2D>(lowedge, highedge, dbnxy) + ProfileBin1D(std::pair<double, double> edges, const Dbn2D& dbnxy) + : Bin1D<Dbn2D>(edges, dbnxy) { } Modified: trunk/include/YODA/ProfileBin2D.h ============================================================================== --- trunk/include/YODA/ProfileBin2D.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/ProfileBin2D.h Fri Jun 15 19:25:00 2012 (r470) @@ -21,19 +21,22 @@ /// @name Constructors //@{ - /// Constructor giving lowedgesX/Y - ProfileBin2D(double lowX, double lowY, double highX, double highY) - : Bin2D<Dbn3D>(lowX, lowY, highX, highY) + /// Make a new, empty bin with two pairs of edges. + ProfileBin2D(double xmin, double ymin, double xmax, double ymax) { + : Bin2D<Dbn3D>(std::make_pair(xmin, ymin), std::make_pair(xmax, ymax)) { } - ProfileBin2D(const std::pair<std::pair<double,double>,std::pair<double,double> >& edges) - : Bin2D<Dbn3D>(edges) + /// Constructor accepting a set of all edges of a bin + ProfileBin2D(const std::pair<double,double> xedges, std::pair<double,double>& yedges) + : Bin2D<Dbn3D>(xedges, yedges) { } - /// Unpersisting constructor - ProfileBin2D(double lowX, double lowY, double highX, double highY, - const Dbn3D& dbnxyz) - : Bin2D<Dbn3D>(lowX, lowY, highX, highY) + /// @brief Make a bin with all the components of a fill history. + /// + /// Mainly intended for internal persistency use. + ProfileBin2D(const std::pair<double, double>& xedges, + const std::pair<double, double>& yedges, const Dbn3D& dbn) + : Bin2D<Dbn3D>(xedges, yedges, dbn) { } /// Copy constructor Modified: trunk/include/YODA/ReaderYODA.h ============================================================================== --- trunk/include/YODA/ReaderYODA.h Fri May 4 11:03:33 2012 (r469) +++ trunk/include/YODA/ReaderYODA.h Fri Jun 15 19:25:00 2012 (r470) @@ -188,11 +188,11 @@ /// Filling a bin struct fillbin { void operator()(const histo1dbin b, qi::unused_type, qi::unused_type) const { - YODA::HistoBin1D bin(b.lowedge, b.highedge, YODA::Dbn1D(b.dbn.numFills, b.dbn.sumW, b.dbn.sumW2, b.dbn.sumWX, b.dbn.sumWX2)); + YODA::HistoBin1D bin(std::make_pair(b.lowedge, b.highedge), YODA::Dbn1D(b.dbn.numFills, b.dbn.sumW, b.dbn.sumW2, b.dbn.sumWX, b.dbn.sumWX2)); _histo1d.bins.push_back(bin); } void operator()(const profile1dbin b, qi::unused_type, qi::unused_type) const { - YODA::ProfileBin1D bin(b.lowedge, b.highedge, YODA::Dbn2D(b.dbn.numFills, b.dbn.sumW, b.dbn.sumW2, b.dbn.sumWX, b.dbn.sumWX2, b.dbn.sumWY, b.dbn.sumWY2, 0.0)); + YODA::ProfileBin1D bin(std::make_pair(b.lowedge, b.highedge), YODA::Dbn2D(b.dbn.numFills, b.dbn.sumW, b.dbn.sumW2, b.dbn.sumWX, b.dbn.sumWX2, b.dbn.sumWY, b.dbn.sumWY2, 0.0)); _profile1d.bins.push_back(bin); } }; @@ -211,7 +211,7 @@ struct fillkeyval { void operator()(const keyval m, qi::unused_type, qi::unused_type) const { _annotations[m.key] = m.val; - } + } }; Modified: trunk/src/Histo2D.cc ============================================================================== --- trunk/src/Histo2D.cc Fri May 4 11:03:33 2012 (r469) +++ trunk/src/Histo2D.cc Fri Jun 15 19:25:00 2012 (r470) @@ -4,7 +4,6 @@ // Copyright (C) 2008-2012 The YODA collaboration (see AUTHORS for details) // #include "YODA/Histo2D.h" -#include "YODA/ProfileBin2D.h" #include "YODA/Scatter3D.h" #include <cmath> using namespace std; @@ -18,8 +17,9 @@ { } - int Histo2D::fill(double x, double y, double weight) { - return _axis.fill(x, y, weight); + void Histo2D::fill(double x, double y, double weight) { + /// @todo TODO, incl. overflows + // return _axis.fill(x, y, weight); } @@ -87,135 +87,133 @@ } - Histo1D Histo2D::cutterX(double atY, const std::string& path, const std::string& title) { - if (!_axis.isGrid()) throw GridError("Attempt to cut a Histo2D that is not a grid!"); + // Histo1D Histo2D::cutterX(double atY, const std::string& path, const std::string& title) { + // if (!_axis.isGrid()) throw GridError("Attempt to cut a Histo2D that is not a grid!"); - if (atY < lowEdgeY() || atY > highEdgeY()) throw RangeError("Y is outside the grid"); - vector<HistoBin1D> tempBins; + // if (atY < lowEdgeY() || atY > highEdgeY()) throw RangeError("Y is outside the grid"); + // vector<HistoBin1D> tempBins; - for (double i = binByCoord(lowEdgeX(), atY).xMin(); i < highEdgeX(); i += binByCoord(i, atY).widthX()) { - const HistoBin2D& b2 = binByCoord(i, atY); - const Dbn1D dbn2(b2.numEntries(), b2.sumW(), b2.sumW2(), b2.sumWX(), b2.sumWX2()); - tempBins.push_back(HistoBin1D(b2.lowEdgeX(), b2.highEdgeX(), dbn2)); - } - - /// Setting under/over flows - Dbn2D underflow; - underflow += _axis.outflows()[7][_axis.getBinRow(_axis.getBinIndex(lowEdgeX(), atY))]; + // for (double i = binByCoord(lowEdgeX(), atY).xMin(); i < highEdgeX(); i += binByCoord(i, atY).widthX()) { + // const HistoBin2D& b2 = binByCoord(i, atY); + // const Dbn1D dbn2(b2.numEntries(), b2.sumW(), b2.sumW2(), b2.sumWX(), b2.sumWX2()); + // tempBins.push_back(HistoBin1D(b2.lowEdgeX(), b2.highEdgeX(), dbn2)); + // } + + // /// Setting under/over flows + // Dbn2D underflow; + // underflow += _axis.outflows()[7][_axis.getBinRow(_axis.getBinIndex(lowEdgeX(), atY))]; + + // Dbn2D overflow; + // overflow += _axis.outflows()[3][_axis.getBinRow(_axis.getBinIndex(lowEdgeX(), atY))]; + + // return Histo1D(tempBins, _axis.totalDbn().transformX(), underflow.transformX(), overflow.transformX(), path, title); + + // } + + + // Histo1D Histo2D::cutterY(double atX, const std::string& path, const std::string& title) { + // if (!_axis.isGrid()) throw GridError("Attempt to cut a Histo2D that is not a grid!"); + + // if (atX < lowEdgeX() || atX > highEdgeX()) throw RangeError("X is outside the grid"); + // vector<HistoBin1D> tempBins; + + // for (double i = binByCoord(atX, lowEdgeY()).yMin(); i < highEdgeY(); i += binByCoord(atX, i).widthY()) { + // const HistoBin2D& b2 = binByCoord(atX, i); + // const Dbn1D dbn2(b2.numEntries(), b2.sumW(), b2.sumW2(), b2.sumWX(), b2.sumWX2()); + // tempBins.push_back(HistoBin1D(b2.lowEdgeY(), b2.highEdgeY(), dbn2)); + // } + + // // Setting under/over flows + // Dbn2D underflow; + // underflow += _axis.outflows()[1][_axis.getBinColumn(_axis.getBinIndex(atX, lowEdgeY()))]; + + // Dbn2D overflow; + // overflow += _axis.outflows()[5][_axis.getBinColumn(_axis.getBinIndex(atX, lowEdgeY()))]; + // Dbn2D total = _axis.totalDbn(); + + // // Making sure that we rotate our distributions, as we are cutting parallel to Y axis now + // total.flipXY(); + // underflow.flipXY(); + // overflow.flipXY(); + + // return Histo1D(tempBins, total.transformX(), underflow.transformX(), overflow.transformX(), path, title); + // } + + + // Profile1D Histo2D::mkProfileX() { + // if (!_axis.isGrid()) throw GridError("Profile1D cannot be made from a histogram that is not a grid!"); + + // vector<ProfileBin1D> prof; + // for(int i = lowEdgeX() + _axis.bin(0).midpoint().first; i < highEdgeX(); i+= _axis.bin(0).widthX()) { + // HistoBin2D& bin(_axis.binByCoord(i, lowEdgeY())); + // HistoBin2D composite(bin.xMin(), bin.xMax(), bin.yMin(), bin.yMax()) ; + // for(int j = lowEdgeY() + _axis.bin(0).midpoint().second; j < highEdgeY(); j += _axis.bin(0).widthY()) { + // composite += _axis.binByCoord(i, j); + // } + // prof.push_back(composite.transformX()); + // } + + // vector<vector<Dbn2D> >& outflows = _axis.outflows(); + + // /// Properly setting an underflow + // Dbn2D underflow; + // underflow += outflows[0][0]; underflow += outflows[6][0]; + // for(size_t i = 0; i < outflows[7].size(); ++i) { + // underflow += outflows[7][i]; + // } + + // /// Setting an overflow + // Dbn2D overflow; + // overflow += outflows[2][0]; overflow += outflows[4][0]; + // for(size_t i = 0; i < outflows[3].size(); ++i) { + // overflow += outflows[3][i]; + // } + + // /// And constructing a profile 1D from all this data + // Profile1D ret(prof, _axis.totalDbn(), underflow, overflow); + // return ret; + + // } + + // Profile1D Histo2D::mkProfileY() { + // if (!_axis.isGrid()) throw GridError("Profile1D cannot be made from a histogram that is not a grid!"); + + // vector<ProfileBin1D> prof; + // for(int i = lowEdgeY() + _axis.bin(0).midpoint().second; i < highEdgeY(); i+= _axis.bin(0).widthY()) { + // HistoBin2D& bin(_axis.binByCoord(i, lowEdgeY())); + // HistoBin2D composite(bin.xMin(), bin.xMax(), bin.yMin(), bin.yMax()) ; + // for(int j = lowEdgeX() + _axis.bin(0).midpoint().first; j < highEdgeX(); j += _axis.bin(0).widthX()) { + // composite += _axis.binByCoord(i, j); + // } + // prof.push_back(composite.transformY()); + // } + + // vector<vector<Dbn2D> >& outflows = _axis.outflows(); + + // /// Properly setting an underflow + // Dbn2D underflow; + // underflow += outflows[0][0]; underflow += outflows[2][0]; + // for(size_t i = 0; i < outflows[1].size(); ++i) { + // underflow += outflows[1][i]; + // } + + // /// Setting an overflow + // Dbn2D overflow; + // overflow += outflows[6][0]; overflow += outflows[4][0]; + // for(size_t i = 0; i < outflows[5].size(); ++i) { + // overflow += outflows[5][i]; + // } + + // /// Setting a flipped total distribution + // Dbn2D td = _axis.totalDbn(); + // td.flipXY(); + + // /// And constructing a profile 1D from all this data + // Profile1D ret(prof, td, underflow, overflow); + // return ret; + // } - Dbn2D overflow; - overflow += _axis.outflows()[3][_axis.getBinRow(_axis.getBinIndex(lowEdgeX(), atY))]; - return Histo1D(tempBins, _axis.totalDbn().transformX(), underflow.transformX(), overflow.transformX(), path, title); - - } - - - Histo1D Histo2D::cutterY(double atX, const std::string& path, const std::string& title) { - if (!_axis.isGrid()) throw GridError("Attempt to cut a Histo2D that is not a grid!"); - - if (atX < lowEdgeX() || atX > highEdgeX()) throw RangeError("X is outside the grid"); - vector<HistoBin1D> tempBins; - - for (double i = binByCoord(atX, lowEdgeY()).yMin(); i < highEdgeY(); i += binByCoord(atX, i).widthY()) { - const HistoBin2D& b2 = binByCoord(atX, i); - const Dbn1D dbn2(b2.numEntries(), b2.sumW(), b2.sumW2(), b2.sumWX(), b2.sumWX2()); - tempBins.push_back(HistoBin1D(b2.lowEdgeY(), b2.highEdgeY(), dbn2)); - } - - // Setting under/over flows - Dbn2D underflow; - underflow += _axis.outflows()[1][_axis.getBinColumn(_axis.getBinIndex(atX, lowEdgeY()))]; - - Dbn2D overflow; - overflow += _axis.outflows()[5][_axis.getBinColumn(_axis.getBinIndex(atX, lowEdgeY()))]; - Dbn2D total = _axis.totalDbn(); - - // Making sure that we rotate our distributions, as we are cutting parallel to Y axis now - total.flipXY(); - underflow.flipXY(); - overflow.flipXY(); - - return Histo1D(tempBins, total.transformX(), underflow.transformX(), overflow.transformX(), path, title); - } - - - Profile1D Histo2D::mkProfileX() { - if (!_axis.isGrid()) throw GridError("Profile1D cannot be made from a histogram that is not a grid!"); - - vector<ProfileBin1D> prof; - for(int i = lowEdgeX() + _axis.bin(0).midpoint().first; i < highEdgeX(); i+= _axis.bin(0).widthX()) { - HistoBin2D& bin(_axis.binByCoord(i, lowEdgeY())); - HistoBin2D composite(bin.xMin(), bin.xMax(), bin.yMin(), bin.yMax()) ; - for(int j = lowEdgeY() + _axis.bin(0).midpoint().second; j < highEdgeY(); j += _axis.bin(0).widthY()) { - composite += _axis.binByCoord(i, j); - } - prof.push_back(composite.transformX()); - } - - vector<vector<Dbn2D> >& outflows = _axis.outflows(); - - /// Properly setting an underflow - Dbn2D underflow; - underflow += outflows[0][0]; underflow += outflows[6][0]; - for(size_t i = 0; i < outflows[7].size(); ++i) { - underflow += outflows[7][i]; - } - - /// Setting an overflow - Dbn2D overflow; - overflow += outflows[2][0]; overflow += outflows[4][0]; - for(size_t i = 0; i < outflows[3].size(); ++i) { - overflow += outflows[3][i]; - } - - /// And constructing a profile 1D from all this data - Profile1D ret(prof, _axis.totalDbn(), underflow, overflow); - return ret; - - } - - Profile1D Histo2D::mkProfileY() { - if (!_axis.isGrid()) throw GridError("Profile1D cannot be made from a histogram that is not a grid!"); - - vector<ProfileBin1D> prof; - for(int i = lowEdgeY() + _axis.bin(0).midpoint().second; i < highEdgeY(); i+= _axis.bin(0).widthY()) { - HistoBin2D& bin(_axis.binByCoord(i, lowEdgeY())); - HistoBin2D composite(bin.xMin(), bin.xMax(), bin.yMin(), bin.yMax()) ; - for(int j = lowEdgeX() + _axis.bin(0).midpoint().first; j < highEdgeX(); j += _axis.bin(0).widthX()) { - composite += _axis.binByCoord(i, j); - } - prof.push_back(composite.transformY()); - } - - vector<vector<Dbn2D> >& outflows = _axis.outflows(); - - /// Properly setting an underflow - Dbn2D underflow; - underflow += outflows[0][0]; underflow += outflows[2][0]; - for(size_t i = 0; i < outflows[1].size(); ++i) { - underflow += outflows[1][i]; - } - - /// Setting an overflow - Dbn2D overflow; - overflow += outflows[6][0]; overflow += outflows[4][0]; - for(size_t i = 0; i < outflows[5].size(); ++i) { - overflow += outflows[5][i]; - } - - /// Setting a flipped total distribution - Dbn2D td = _axis.totalDbn(); - td.flipXY(); - - /// And constructing a profile 1D from all this data - Profile1D ret(prof, td, underflow, overflow); - return ret; - } - - - /// @todo Check how finding the correct bins works in the case of - /// a sparse representation, and if it is decent, code it in here. Scatter3D divide(const Histo2D& numer, const Histo2D& denom) { if (numer != denom) throw GridError("The two histos are not equivalently binned!"); Scatter3D tmp; Modified: trunk/src/Makefile.am ============================================================================== --- trunk/src/Makefile.am Fri May 4 11:03:33 2012 (r469) +++ trunk/src/Makefile.am Fri Jun 15 19:25:00 2012 (r470) @@ -13,9 +13,8 @@ WriterYODA.cc \ Reader.cc \ ReaderAIDA.cc \ - ReaderYODA.cc - -# Histo2D.cc \ + ReaderYODA.cc \ + Histo2D.cc # Profile2D.cc \ # Scatter3D.cc
More information about the yoda-svn mailing list |