Kaynağa Gözat

Adds Mean and Range Reduce classes. Integrates Function type into
Filters. Reimplements TH2-based containers using new class hierarchy.

Caleb Fangmeier 7 yıl önce
ebeveyn
işleme
01b069d2db
5 değiştirilmiş dosya ile 261 ekleme ve 114 silme
  1. 4 1
      CMakeLists.txt
  2. 58 29
      analysis/TTTT_Analysis.cpp
  3. 49 8
      filval/filter.hpp
  4. 28 13
      filval/value.hpp
  5. 122 63
      filval_root/container.hpp

+ 4 - 1
CMakeLists.txt

@@ -50,7 +50,10 @@ IF(DOXYGEN_FOUND)
 ENDIF(DOXYGEN_FOUND)
 
 FIND_PACKAGE(ROOT REQUIRED)
-INCLUDE_DIRECTORIES(SYSTEM ${ROOT_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
+INCLUDE_DIRECTORIES(SYSTEM ${ROOT_INCLUDE_DIR}
+                           ${CMAKE_CURRENT_SOURCE_DIR}
+                           ${CMAKE_CURRENT_SOURCE_DIR}/filval
+                           ${CMAKE_CURRENT_SOURCE_DIR}/filval_root)
 LINK_LIBRARIES(${ROOT_LIBRARIES})
 
 

+ 58 - 29
analysis/TTTT_Analysis.cpp

@@ -1,3 +1,36 @@
+/**
+ * @file
+ * @author  Caleb Fangmeier <caleb@fangmeier.tech>
+ * @version 0.1
+ *
+ * @section LICENSE
+ *
+ *
+ * MIT License
+ *
+ * Copyright (c) 2017 Caleb Fangmeier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @section DESCRIPTION
+ * Main analysis routine file
+ */
 #include <iostream>
 #include <vector>
 #include <utility>
@@ -6,9 +39,8 @@
 #include "TTree.h"
 #include "TCanvas.h"
 
-#include "filval/filval.hpp"
-#include "filval_root/filval_root.hpp"
-#include "filval/log.hpp"
+#include "filval.hpp"
+#include "filval_root.hpp"
 
 #include "MiniTreeDataSet.hpp"
 
@@ -50,14 +82,11 @@ void enable_branches(MiniTreeDataSet& mt){
 }
 
 void declare_values(MiniTreeDataSet& mt){
-    auto& mean = GenFunction::register_function<float(vector<float>)>("mean", FUNC(([](vector<float> v){
-            int n = 0;
-            float sum = 0;
-            for (float e : v){
-                n++;
-                sum += e;
-            }
-            return n>0 ? sum / n : 0;
+    auto& get_energy = GenFunction::register_function<float(float,float,float,float)>("get_energy",
+            FUNC(([](float pt, float eta, float phi, float m){
+                TLorentzVector t;
+                t.SetPtEtaPhiM(pt, eta, phi, m);
+                return t.E();
             })));
 
     new WrapperVector<float>("nLepGood", "LepGood_pt", "LepGood_pt");
@@ -65,25 +94,23 @@ void declare_values(MiniTreeDataSet& mt){
     new WrapperVector<float>("nLepGood", "LepGood_phi", "LepGood_phi");
     new WrapperVector<float>("nLepGood", "LepGood_mass", "LepGood_mass");
 
-    auto& get_energy = GenFunction::register_function<float(float,float,float,float)>("get_energy",
-            FUNC(([](float pt, float eta, float phi, float m){
-                TLorentzVector t;
-                t.SetPtEtaPhiM(pt, eta, phi, m);
-                return t.E();
-            })));
 
-    auto lepton_energy = new ZipMapFour<float, float>(get_energy, "LepGood_pt", "LepGood_eta", "LepGood_phi", "LepGood_mass");
-    GenValue::alias("lepton_energy", lepton_energy);
+    new ZipMapFour<float, float>(get_energy, "LepGood_pt", "LepGood_eta", "LepGood_phi", "LepGood_mass",
+                                 "lepton_energy");
+
+    new Pair<vector<float>,vector<float>>("lepton_energy", "LepGood_pt", "lepton_energy_lepton_pt");
 
-    GenValue::alias("avg_lepton_energy", new Reduce<float>(mean , "lepton_energy"));
-    GenValue::alias("max_lepton_energy", new Max<float>("lepton_energy"));
+    new Max<float>("lepton_energy", "lepton_energy_max");
+    new Min<float>("lepton_energy", "lepton_energy_min");
+    new Range<float>("lepton_energy", "lepton_energy_range");
+    new Mean<float>("lepton_energy", "lepton_energy_mean");
 
 
-    new Filter("nLepGood>=3", [nLepGood=lookup("nLepGood")](){
-            return dynamic_cast<Value<int>*>(nLepGood)->get_value() >=3;});
+    new Filter("nLepGood>=3", FUNC(([nLepGood=lookup("nLepGood")](){
+            return dynamic_cast<Value<int>*>(nLepGood)->get_value() >=3;})));
 
-    new Filter("nLepGood<=4", [nLepGood=lookup("nLepGood")](){
-            return dynamic_cast<Value<int>*>(nLepGood)->get_value() <=4;});
+    new Filter("nLepGood<=4", FUNC(([nLepGood=lookup("nLepGood")](){
+            return dynamic_cast<Value<int>*>(nLepGood)->get_value() <=4;})));
     new RangeFilter<int>("3<=nLepGood<5", dynamic_cast<Value<int>*>(lookup("nLepGood")), 3, 5);
 }
 
@@ -91,7 +118,10 @@ void declare_containers(MiniTreeDataSet& mt){
     mt.register_container(new ContainerTH1I("lepton_count", "Lepton Multiplicity", lookup("nLepGood"), 8, 0, 8));
     mt.register_container(new ContainerTH1I("top_quark_count", "Top Quark Multiplicity", lookup("nGenTop"), 8, 0, 8));
 
-    mt.register_container(new ContainerTH1FMany("lepton_pt_all", "Lepton Pt - All", lookup("LepGood_pt"), 50, 0, 500));
+    mt.register_container(new ContainerTH1FMany("lepton_energy_all", "Lepton Energy - All", lookup("lepton_energy"), 50, 0, 500));
+    mt.register_container(new ContainerTH1F("lepton_energy_max", "Lepton Energy - Max", lookup("lepton_energy_max"), 50, 0, 500));
+    mt.register_container(new ContainerTH1F("lepton_energy_min", "Lepton Energy - Min", lookup("lepton_energy_min"), 50, 0, 500));
+    mt.register_container(new ContainerTH1F("lepton_energy_rng", "Lepton Energy - Range", lookup("lepton_energy_range"), 50, 0, 500));
 
     mt.register_container(new ContainerTH1I("nLepGood2", "Lepton Multiplicity", lookup("nLepGood"), 10, 0, 10));
     mt.get_container("nLepGood2")->add_filter(lookup_filter("3<=nLepGood<5"));
@@ -101,9 +131,8 @@ void declare_containers(MiniTreeDataSet& mt){
 
     mt.register_container(new ContainerTGraph("nLepvsnJet", new Pair<int, int>("nLepGood", "nJet") ));
 
-    mt.register_container(new ContainerTH1F("avg_lepton_energy", "Average Lepton Energy", lookup("avg_lepton_energy"), 50, 0, 500));
-    mt.register_container(new ContainerTH1F("max_lepton_energy", "Maximum Lepton Energy", lookup("max_lepton_energy"), 50, 0, 500));
-
+    mt.register_container(new ContainerTH2FMany("lepton_energy_vs_pt", "Lepton Energy - Range", lookup("lepton_energy_lepton_pt"),
+                                               50, 0, 500, 50, 0, 500));
 }
 
 void run_analysis(const std::string& filename){

+ 49 - 8
filval/filter.hpp

@@ -1,35 +1,76 @@
+/**
+ * @file
+ * @author  Caleb Fangmeier <caleb@fangmeier.tech>
+ * @version 0.1
+ *
+ * @section LICENSE
+ *
+ *
+ * MIT License
+ *
+ * Copyright (c) 2017 Caleb Fangmeier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * @section DESCRIPTION
+ * A Filter is a special type of derived value that can only return a boolean.
+ * Container objects have a vector of filters that control if a "fill" call
+ * actually places data into the container or not. This file contains a variety
+ * of generic filters to aide in analysis.
+ */
 #ifndef filter_h
 #define filter_h
 #include <iostream>
 #include <functional>
 #include "value.hpp"
-/* A Filter is a special type of derived value that can only return a boolean.
- * Container objects have a vector of filters that control if a "fill" call
- * actually places data into the container or not.
- */
 namespace fv {
 
 class Filter : public DerivedValue<bool>{
     private:
-        std::function<bool()> filter_function;
+        Function<bool()>& filter_function;
+
         void update_value(){
             value = filter_function();
         }
     public:
-        Filter(const std::string& name, std::function<bool()> filter_function)
+        Filter(const std::string& name, std::function<bool()> filter_function, const std::string& impl="")
           :DerivedValue<bool>(name),
-           filter_function(filter_function){ }
+           filter_function(GenFunction::register_function<bool()>("filter::"+name, filter_function, impl)){ }
 
+        /** Return a new filter that is the conjuction of the two source
+         * filters.
+         */
         Filter* operator*(Filter *f){
             auto new_name = this->get_name() + "&&" + f->get_name();
             return new Filter(new_name, [this, f](){return this->get_value() && f->get_value();});
         }
 
+        /** Return a new filter that is the disjunction of the two source
+         * filters.
+         */
         Filter* operator+(Filter *f){
             auto new_name = this->get_name() + "||" + f->get_name();
             return new Filter(new_name, [this, f](){return this->get_value() || f->get_value();});
         }
 
+        /** Return a new filter that is the negation of the source filter.
+         */
         Filter* operator!(){
             auto new_name = std::string("!(") + this->get_name() + std::string(")");
             return new Filter(new_name, [this](){return !this->get_value();});
@@ -44,7 +85,7 @@ class RangeFilter : public Filter{
           Filter(name, [test_value, range_low, range_high]{
                   T val = test_value->get_value();
                   return (val >= range_low) && (val < range_high);
-                  }){ }
+                  }) { }
 };
 }
 #endif // filter_h

+ 28 - 13
filval/value.hpp

@@ -59,7 +59,7 @@
  */
 namespace fv{
 
-bool in_register_function = false;
+/* bool in_register_function = false; */
 template<typename> class Function; // undefined
 /**
  * Parent class to all Function classes. Holds a class-level collection of all
@@ -69,6 +69,8 @@ class GenFunction {
     private:
         std::string name;
         std::string impl;
+    protected:
+        inline static bool in_register_function=false;
 
     public:
         /**
@@ -123,7 +125,7 @@ class GenFunction {
             if (GenFunction::function_registry[name] != nullptr){
                 func = dynamic_cast<Function<T>*>(GenFunction::function_registry[name]);
                 if (func == nullptr){
-                    ERROR("Trying to register function which has already been registerd with a different type");
+                    ERROR("Trying to register function which has already been registered with a different type");
                 }
             } else {
                 func = new Function<T>(name, impl, f);
@@ -155,7 +157,7 @@ class Function<R(ArgTypes...)> : public GenFunction {
         Function(const std::string& name, const std::string& impl, std::function<R(ArgTypes...)> f)
           :GenFunction(name, impl), f(f){
             if (!in_register_function) {
-                WARNING("Don't instantiate Function objects directly! Use register_function instead.");
+                WARNING("Don't instantiate Function objects directly! Use GenFunction::register_function instead.");
             }
           }
         Function(const std::string& name, std::function<R(ArgTypes...)> f)
@@ -385,7 +387,6 @@ class DerivedValue : public Value<T>{
  * object containing the array itself as well as another Value object
  * containing the size of that array. Currently, update_value will simply copy
  * the contents of the array into the interally held vector.
- * \todo avoid an unneccessary copy and set the vectors data directly.
  */
 template <typename T>
 class WrapperVector : public DerivedValue<std::vector<T> >{
@@ -396,10 +397,7 @@ class WrapperVector : public DerivedValue<std::vector<T> >{
         void update_value(){
             int n = size->get_value();
             T* data_ref = data->get_value();
-            this->value.resize(n);
-            for (int i=0; i<n; i++){
-                this->value[i] = *(data_ref+i);
-            }
+            this->value.assign(data_ref, data_ref+n);
         }
 
     public:
@@ -532,8 +530,9 @@ template <typename T>
 class Min : public Reduce<T>{
     public:
         Min(const std::string& v_name, const std::string alias="")
-          :Reduce<T>(new Function<T(std::vector<T>)>("min", [](std::vector<T> vec){
-                         return *std::min_element(vec.begin(), vec.end());}),
+          :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("min",
+                      FUNC(([](std::vector<T> vec){
+                         return *std::min_element(vec.begin(), vec.end());}))),
                      v_name, alias) { }
 };
 
@@ -544,10 +543,25 @@ template <typename T>
 class Mean : public Reduce<T>{
     public:
         Mean(const std::string& v_name, const std::string alias="")
-          :Reduce<T>(new Function<T(std::vector<T>)>("mean", [](std::vector<T> vec){
+          :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("mean",
+                      FUNC(([](std::vector<T> vec){
                         int n = 0; T sum = 0;
                         for (T e : vec){ n++; sum += e; }
-                        return n>0 ? sum / n : 0; }),
+                        return n>0 ? sum / n : 0; }))),
+                     v_name, alias) { }
+};
+
+/**
+ * Calculate the range of the values in a vector
+ */
+template <typename T>
+class Range : public Reduce<T>{
+    public:
+        Range(const std::string& v_name, const std::string alias="")
+          :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("range",
+                      FUNC(([](std::vector<T> vec){
+                        auto minmax = std::minmax_element(vec.begin(), vec.end());
+                        return (*minmax.second) - (*minmax.first); }))),
                      v_name, alias) { }
 };
 
@@ -558,7 +572,8 @@ template <typename T>
 class ElementOf : public Reduce<T>{
     public:
         ElementOf(Value<int>* index, const std::string& v_name, const std::string alias="")
-          :Reduce<T>(new Function<T(std::vector<T>)>("elementOf", [index](std::vector<T> vec){return vec[index->get_value()];}),
+          :Reduce<T>(GenFunction::register_function<T(std::vector<T>)>("elementOf",
+                      FUNC(([index](std::vector<T> vec){return vec[index->get_value()];}))),
                      v_name, alias) { }
         ElementOf(const std::string& name, int index, const std::string& v_name, const std::string alias="")
           :Reduce<T>(name, [index](std::vector<T> vec){return vec[index];}, v_name, alias) { }

+ 122 - 63
filval_root/container.hpp

@@ -8,7 +8,7 @@
 #include "TGraph.h"
 #include "TROOT.h"
 
-#include "../filval/filval.hpp"
+#include "filval.hpp"
 
 namespace fv::root::util{
 void _save_img(TObject* container, const std::string& fname){
@@ -47,6 +47,10 @@ class ContainerTH1 : public Container<TH1>{
     private:
         void _fill(){
             if (container == nullptr){
+                if (value == nullptr){
+                    CRITICAL("Container: \"" << get_name() << "\" has a null Value object. "
+                             << "Probably built with imcompatible type",-1);
+                }
                 init_TH1();
             }
             _do_fill(value->get_value());
@@ -148,68 +152,124 @@ class ContainerTH1IMany : public _ContainerTH1I<std::vector<int>>{
 };
 
 
-/* template <typename T> */
-/* class ContainerTH2 : public Container<TH2>{ */
-/*     private: */
-/*         void _fill(){ */
-/*             if (container == nullptr){ */
-/*                 init_TH2(); */
-/*             } */
-/*             std::pair<T, T> val = value->get_value(); */
-/*             container->Fill(val.first, val.second); */
-/*         } */
-
-/*     protected: */
-/*         std::string title; */
-/*         int nbins_x; */
-/*         int nbins_y; */
-/*         T low_x; */
-/*         T low_y; */
-/*         T high_x; */
-/*         T high_y; */
-/*         Value<std::pair<T, T> > *value; */
-/*         virtual void init_TH2() = 0; */
-
-/*     public: */
-/*         explicit ContainerTH2(const std::string& name, const std::string& title, */
-/*                       int nbins_x, double low_x, double high_x, */
-/*                       int nbins_y, double low_y, double high_y, */
-/*                       GenValue* value) */
-/*           :Container<TH2>(name, nullptr), */
-/*            nbins_x(nbins_x), low_x(low_x), high_x(high_x), */
-/*            nbins_y(nbins_y), low_y(low_y), high_y(high_y), */
-/*            value(dynamic_cast<Value<T>*>(value)) { } */
-
-/*         void save_as(const std::string& fname, const SaveOption& option = SaveOption::PNG) { */
-/*             util::_save_as(get_container(), fname, option); */
-/*         } */
-
-/*         void save(const SaveOption& option = SaveOption::PNG) { */
-/*             save_as(this->get_name(), option); */
-/*         } */
-/* }; */
-
-/* class ContainerTH2D : public ContainerTH2<double>{ */
-/*     using ContainerTH2::ContainerTH2; */
-/*     void init_TH2(){ */
-/*         this->container = new TH2D(this->get_name().c_str(), title.c_str(), nbins_x, low_x, high_x, nbins_y, low_y, high_y); */
-/*     } */
-/* }; */
-
-/* class ContainerTH2F : public ContainerTH2<float>{ */
-/*     using ContainerTH2::ContainerTH2; */
-/*     void init_TH2(){ */
-/*         this->container = new TH2F(this->get_name().c_str(), title.c_str(), nbins_x, low_x, high_x, nbins_y, low_y, high_y); */
-/*     } */
-/* }; */
-
-/* class ContainerTH2I : public ContainerTH2<int>{ */
-/*     using ContainerTH2::ContainerTH2; */
-/*     void init_TH2(){ */
-/*         this->container = new TH2I(this->get_name().c_str(), title.c_str(), nbins_x, low_x, high_x, nbins_y, low_y, high_y); */
-/*     } */
-/* }; */
+template <typename V, typename D>
+class ContainerTH2 : public Container<TH2>{
+    private:
+        void _fill(){
+            if (container == nullptr){
+                if (value == nullptr){
+                    CRITICAL("Container: \"" << get_name() << "\" has a null Value object. "
+                             << "Probably built with imcompatible type",-1);
+                }
+                init_TH2();
+            }
+            _do_fill(value->get_value());
+        }
+
+    protected:
+        std::string title;
+        int nbins_x;
+        int nbins_y;
+        D low_x;
+        D low_y;
+        D high_x;
+        D high_y;
+        Value<std::pair<V,V>> *value;
+        virtual void init_TH2() = 0;
+        virtual void _do_fill(std::pair<V,V>& val) = 0;
+
+    public:
+        explicit ContainerTH2(const std::string& name, const std::string& title,
+                              GenValue* value,
+                              int nbins_x, D low_x, D high_x,
+                              int nbins_y, D low_y, D high_y)
+          :Container<TH2>(name, nullptr),
+           nbins_x(nbins_x), low_x(low_x), high_x(high_x),
+           nbins_y(nbins_y), low_y(low_y), high_y(high_y),
+           value(dynamic_cast<Value<std::pair<V, V>>*>(value)) { }
+
+        void save_as(const std::string& fname, const SaveOption& option = SaveOption::PNG) {
+            util::_save_as(get_container(), fname, option);
+        }
+};
+
+template <typename V>
+class _ContainerTH2D : public ContainerTH2<V, double>{
+    using ContainerTH2<V, double>::ContainerTH2;
+    void init_TH2(){
+        this->container = new TH2D(this->get_name().c_str(), this->title.c_str(),
+                                   this->nbins_x, this->low_x, this->high_x,
+                                   this->nbins_y, this->low_y, this->high_y);
+    }
+};
+
+class ContainerTH2D : public _ContainerTH2D<double>{
+    using _ContainerTH2D<double>::_ContainerTH2D;
+    void _do_fill(std::pair<double,double>& val){
+        this->container->Fill(val.first, val.second);
+    }
+};
+
+class ContainerTH2DMany : public _ContainerTH2D<std::vector<double>>{
+    using _ContainerTH2D<std::vector<double>>::_ContainerTH2D;
+    void _do_fill(std::pair<std::vector<double>,std::vector<double>>& val){
+        int min_size = std::min(val.first.size(), val.second.size());
+        for(int i=0; i<min_size; i++)
+            this->container->Fill(val.first[i],val.second[i]);
+    }
+};
+
+template <typename V>
+class _ContainerTH2F : public ContainerTH2<V, float>{
+    using ContainerTH2<V, float>::ContainerTH2;
+    void init_TH2(){
+        this->container = new TH2F(this->get_name().c_str(), this->title.c_str(),
+                                   this->nbins_x, this->low_x, this->high_x,
+                                   this->nbins_y, this->low_y, this->high_y);
+    }
+};
+
+class ContainerTH2F : public _ContainerTH2F<float>{
+    using _ContainerTH2F<float>::_ContainerTH2F;
+    void _do_fill(std::pair<float,float>& val){
+        this->container->Fill(val.first, val.second);
+    }
+};
 
+class ContainerTH2FMany : public _ContainerTH2F<std::vector<float>>{
+    using _ContainerTH2F<std::vector<float>>::_ContainerTH2F;
+    void _do_fill(std::pair<std::vector<float>,std::vector<float>>& val){
+        int min_size = std::min(val.first.size(), val.second.size());
+        for(int i=0; i<min_size; i++)
+            this->container->Fill(val.first[i],val.second[i]);
+    }
+};
+
+template <typename V>
+class _ContainerTH2I : public ContainerTH2<V, int>{
+    using ContainerTH2<V, int>::ContainerTH2;
+    void init_TH2(){
+        this->container = new TH2I(this->get_name().c_str(), this->title.c_str(),
+                                   this->nbins_x, this->low_x, this->high_x,
+                                   this->nbins_y, this->low_y, this->high_y);
+    }
+};
+
+class ContainerTH2I : public _ContainerTH2I<int>{
+    using _ContainerTH2I<int>::_ContainerTH2I;
+    void _do_fill(std::pair<int,int>& val){
+        this->container->Fill(val.first, val.second);
+    }
+};
+
+class ContainerTH2IMany : public _ContainerTH2I<std::vector<int>>{
+    using _ContainerTH2I<std::vector<int>>::_ContainerTH2I;
+    void _do_fill(std::pair<std::vector<int>,std::vector<int>>& val){
+        int min_size = std::min(val.first.size(), val.second.size());
+        for(int i=0; i<min_size; i++)
+            this->container->Fill(val.first[i],val.second[i]);
+    }
+};
 
 class ContainerTGraph : public Container<TGraph>{
     private:
@@ -234,7 +294,6 @@ class ContainerTGraph : public Container<TGraph>{
                 delete container;
                 container = new TGraph(x_data.size(), x_data.data(), y_data.data());
                 container->SetName(get_name().c_str());
-                std::cout << "name: " << container->GetName() << std::endl;
                 data_modified = false;
             }
             return container;