Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 12:54:12

0001 #ifndef DataFormats_NanoAOD_MergeableCounterTable_h
0002 #define DataFormats_NanoAOD_MergeableCounterTable_h
0003 
0004 #include "FWCore/Utilities/interface/Exception.h"
0005 #include <vector>
0006 #include <string>
0007 #include <algorithm>
0008 
0009 namespace nanoaod {
0010 
0011   class MergeableCounterTable {
0012   public:
0013     MergeableCounterTable() {}
0014     typedef long long int_accumulator;  // we accumulate in long long int, to avoid overflow
0015     typedef double float_accumulator;   // we accumulate in double, to preserve precision
0016 
0017     template <typename T>
0018     struct SingleColumn {
0019       typedef T value_type;
0020       SingleColumn() {}
0021       SingleColumn(const std::string& aname, const std::string& adoc, T avalue = T())
0022           : name(aname), doc(adoc), value(avalue) {}
0023       std::string name, doc;
0024       T value;
0025       void operator+=(const SingleColumn<T>& other) {
0026         if (!compatible(other))
0027           throw cms::Exception("LogicError",
0028                                "Trying to merge " + name + " with " + other.name + " failed compatibility test.\n");
0029         value += other.value;
0030       }
0031       bool compatible(const SingleColumn<T>& other) {
0032         return name == other.name;  // we don't check the doc, not needed
0033       }
0034     };
0035     typedef SingleColumn<float_accumulator> FloatColumn;
0036     typedef SingleColumn<int_accumulator> IntColumn;
0037 
0038     template <typename T>
0039     struct SingleWithNormColumn : SingleColumn<T> {
0040       SingleWithNormColumn() { norm = 0; }
0041       SingleWithNormColumn(const std::string& aname, const std::string& adoc, T avalue = T(), const double anorm = 0)
0042           : SingleColumn<T>(aname, adoc, avalue), norm(anorm) {}
0043       double norm;
0044       void operator+=(const SingleWithNormColumn<T>& other) {
0045         if (!this->compatible(other))
0046           throw cms::Exception(
0047               "LogicError", "Trying to merge " + this->name + " with " + other.name + " failed compatibility test.\n");
0048         auto newNorm = norm + other.norm;
0049         this->value = (newNorm != 0) ? (this->value * norm + other.value * other.norm) / newNorm : 0;
0050         norm = newNorm;
0051       }
0052     };
0053     typedef SingleWithNormColumn<float_accumulator> FloatWithNormColumn;
0054 
0055     template <typename T>
0056     struct VectorColumn {
0057       typedef T element_type;
0058       VectorColumn() {}
0059       VectorColumn(const std::string& aname, const std::string& adoc, unsigned int size)
0060           : name(aname), doc(adoc), values(size, T()) {}
0061       VectorColumn(const std::string& aname, const std::string& adoc, const std::vector<T>& somevalues)
0062           : name(aname), doc(adoc), values(somevalues) {}
0063       std::string name, doc;
0064       std::vector<T> values;
0065       void operator+=(const VectorColumn<T>& other) {
0066         if (!compatible(other))
0067           throw cms::Exception("LogicError",
0068                                "Trying to merge " + name + " with " + other.name + " failed compatibility test.\n");
0069         for (unsigned int i = 0, n = values.size(); i < n; ++i) {
0070           values[i] += other.values[i];
0071         }
0072       }
0073       bool compatible(const VectorColumn<T>& other) {
0074         return name == other.name && values.size() == other.values.size();  // we don't check the doc, not needed
0075       }
0076     };
0077     typedef VectorColumn<float_accumulator> VFloatColumn;
0078     typedef VectorColumn<int_accumulator> VIntColumn;
0079 
0080     template <typename T>
0081     struct VectorWithNormColumn : VectorColumn<T> {
0082       double norm;
0083       VectorWithNormColumn() { norm = 0; }
0084       VectorWithNormColumn(const std::string& aname, const std::string& adoc, unsigned int size, double anorm = 0)
0085           : VectorColumn<T>(aname, adoc, size), norm(anorm) {}
0086       VectorWithNormColumn(const std::string& aname,
0087                            const std::string& adoc,
0088                            const std::vector<T>& somevalues,
0089                            double anorm = 0)
0090           : VectorColumn<T>(aname, adoc, somevalues), norm(anorm) {}
0091       void operator+=(const VectorWithNormColumn<T>& other) {
0092         if (!this->compatible(other))
0093           throw cms::Exception(
0094               "LogicError", "Trying to merge " + this->name + " with " + other.name + " failed compatibility test.\n");
0095         auto newNorm = norm + other.norm;
0096         for (unsigned int i = 0, n = this->values.size(); i < n; ++i) {
0097           this->values[i] =
0098               (newNorm != 0) ? (this->values[i] * norm + other.values[i] * other.norm) / (norm + other.norm) : 0;
0099         }
0100         norm = newNorm;
0101       }
0102     };
0103     typedef VectorWithNormColumn<float_accumulator> VFloatWithNormColumn;
0104 
0105     const std::vector<FloatColumn>& floatCols() const { return floatCols_; }
0106     const std::vector<VFloatColumn>& vfloatCols() const { return vfloatCols_; }
0107     const std::vector<FloatWithNormColumn>& floatWithNormCols() const { return floatWithNormCols_; }
0108     const std::vector<VFloatWithNormColumn>& vfloatWithNormCols() const { return vfloatWithNormCols_; }
0109     const std::vector<IntColumn>& intCols() const { return intCols_; }
0110     const std::vector<VIntColumn>& vintCols() const { return vintCols_; }
0111 
0112     template <typename F>
0113     void addFloat(const std::string& name, const std::string& doc, F value) {
0114       floatCols_.push_back(FloatColumn(name, doc, value));
0115     }
0116 
0117     template <typename F>
0118     void addFloatWithNorm(const std::string& name, const std::string& doc, F value, double norm) {
0119       floatWithNormCols_.push_back(FloatWithNormColumn(name, doc, value, norm));
0120     }
0121 
0122     template <typename I>
0123     void addInt(const std::string& name, const std::string& doc, I value) {
0124       intCols_.push_back(IntColumn(name, doc, value));
0125     }
0126 
0127     template <typename F>
0128     void addVFloat(const std::string& name, const std::string& doc, const std::vector<F> values) {
0129       vfloatCols_.push_back(VFloatColumn(name, doc, values.size()));
0130       std::copy(values.begin(), values.end(), vfloatCols_.back().values.begin());
0131     }
0132 
0133     template <typename F>
0134     void addVFloatWithNorm(const std::string& name, const std::string& doc, const std::vector<F> values, double norm) {
0135       vfloatWithNormCols_.push_back(VFloatWithNormColumn(name, doc, values.size(), norm));
0136       std::copy(values.begin(), values.end(), vfloatWithNormCols_.back().values.begin());
0137     }
0138 
0139     template <typename I>
0140     void addVInt(const std::string& name, const std::string& doc, const std::vector<I> values) {
0141       vintCols_.push_back(VIntColumn(name, doc, values.size()));
0142       std::copy(values.begin(), values.end(), vintCols_.back().values.begin());
0143     }
0144 
0145     bool mergeProduct(const MergeableCounterTable& other) {
0146       if (!tryMerge(intCols_, other.intCols_))
0147         return false;
0148       if (!tryMerge(vintCols_, other.vintCols_))
0149         return false;
0150       if (!tryMerge(floatCols_, other.floatCols_))
0151         return false;
0152       if (!tryMerge(vfloatCols_, other.vfloatCols_))
0153         return false;
0154       if (!tryMerge(floatWithNormCols_, other.floatWithNormCols_))
0155         return false;
0156       if (!tryMerge(vfloatWithNormCols_, other.vfloatWithNormCols_))
0157         return false;
0158       return true;
0159     }
0160 
0161     void swap(MergeableCounterTable& iOther) {
0162       floatCols_.swap(iOther.floatCols_);
0163       vfloatCols_.swap(iOther.vfloatCols_);
0164       floatWithNormCols_.swap(iOther.floatWithNormCols_);
0165       vfloatWithNormCols_.swap(iOther.vfloatWithNormCols_);
0166       intCols_.swap(iOther.intCols_);
0167       vintCols_.swap(iOther.vintCols_);
0168     }
0169 
0170   private:
0171     std::vector<FloatColumn> floatCols_;
0172     std::vector<VFloatColumn> vfloatCols_;
0173     std::vector<FloatWithNormColumn> floatWithNormCols_;
0174     std::vector<VFloatWithNormColumn> vfloatWithNormCols_;
0175     std::vector<IntColumn> intCols_;
0176     std::vector<VIntColumn> vintCols_;
0177 
0178     template <typename T>
0179     bool tryMerge(std::vector<T>& one, const std::vector<T>& two) {
0180       for (auto y : two) {
0181         auto x = std::find_if(one.begin(), one.end(), [&y](const T& x) { return x.name == y.name; });
0182         if (x == one.end())
0183           one.push_back(y);
0184         else
0185           (*x) += y;
0186       }
0187       return true;
0188     }
0189   };
0190 
0191 }  // namespace nanoaod
0192 
0193 #endif