Browse Source

Adds example code for filval and the beginnings of TMVA integration in filval_root

Caleb Fangmeier 7 years ago
parent
commit
9a4380809f
5 changed files with 305 additions and 77 deletions
  1. 12 9
      api.hpp
  2. 97 0
      examples/example1.cpp
  3. 74 0
      examples/example2.cpp
  4. 52 0
      examples/example3.cpp
  5. 70 68
      value.hpp

+ 12 - 9
api.hpp

@@ -29,6 +29,14 @@
  * SOFTWARE.
  *
  * @section DESCRIPTION
+ * This is the main api for FilVal. Users should try to avoid instantiating
+ * Value objects directly, but rather use these functions. There are multiple
+ * reasons for this. First of all, these functions do the extra work of making
+ * sure that an identical Value doesn't already exist. If one does, it returns
+ * the old Value object rather than creating a new one. The second reason is
+ * that C++ allows type deduction for functions so one can often leave out the
+ * type definitions to produce shorter, more readable, code. This cannot be
+ * done when creating templated objects directly.
  */
 #ifndef API_HPP
 #define API_HPP
@@ -39,28 +47,23 @@ namespace fv{
 
     template<typename T>
     Value<T>* lookup(const std::string& name){
-        GenValue* gv = GenValue::get_value(name);
-        if (gv == nullptr){
+        Value<T>* tv = GenValue::get_value<T>(name);
+        if (tv == nullptr){
             CRITICAL("Could not find alias or value \"" << name << "\"."
                      <<" I'll tell you the ones I know about." << std::endl
                      << GenValue::summary(), -1);
         }
-        Value<T>* tv = dynamic_cast<Value<T>*>(gv);
-        if(tv == nullptr){
-            CRITICAL("Value: \""+gv->get_name() + "\" has improper type.",-1);
-        }
         return tv;
     }
 
     template<typename T>
     bool check_exists(const std::string name){
-        GenValue* gv = GenValue::get_value(name);
-        Value<T>* tv = dynamic_cast<Value<T>*>(gv);
+        Value<T>* tv = GenValue::get_value<T>(name);
         return tv != nullptr;
     }
 
     ObsFilter* lookup_obs_filter(const std::string& name){
-        ObsFilter* f =  dynamic_cast<ObsFilter*>(GenValue::get_value(name));
+        ObsFilter* f =  dynamic_cast<ObsFilter*>(GenValue::get_value<bool>(name));
         if(f == nullptr){
             CRITICAL("ObsFilter: "+f->get_name() + "has improper type.",-1);
         }

+ 97 - 0
examples/example1.cpp

@@ -0,0 +1,97 @@
+/**
+ * @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 short example demonstrating some of the basic functionality of the FilVal
+ * Value system.
+ */
+
+#include <iostream>
+#include <utility>
+
+#include "filval/filval.hpp"
+
+int main(int argc, const char* argv[]){
+    // Initialize logging. Let's not worry about what is being logged right now
+    // and just redirect it to /dev/null so it doesn't appear on the screen.
+    fv::util::Log::init_logger("/dev/null", fv::util::LogPriority::kLogDebug);
+
+    // declare a helper function to print out a std::pair object
+    auto print_pair = [](fv::Value<std::pair<double, double>>* dp){
+        std::pair<double, double> p = dp->get_value();
+        std::cout << "(" << p.first << ", " << p.second << ")\n";
+    };
+
+    // These variables are the "Values" that will be observed. Think of these
+    // as sources of data that will be updated as new observations are loaded.
+    double x = 12;
+    double y = 13;
+
+    // This is where the fun begins. Here we declare a couple ObservedValue
+    // objects. these are basically just fancy wrappers around the x, and y
+    // variables declared above. They have the job of supplying the value
+    // stored by x and y when requested.
+    fv::ObservedValue<double> x_val("x", &x);
+    fv::ObservedValue<double> y_val("y", &y);
+
+    // Now that we have a few source values, let's compose them together into a
+    // pair. The fv api defines a function to do this: fv::pair. This function
+    // takes pointers to two Value objects and creates a new value that is a
+    // std::pair of these objects.
+    fv::Value<std::pair<double, double>>* dp = fv::pair(&x_val, &y_val);
+
+    // If we call the print_pair function that we declared earlier with the new
+    // value object, we can see that, indeed, we see the correct output
+    // (12, 13)
+    print_pair(dp);
+
+    // Now let's update the values of x and y to both be 2. Normally this job
+    // will be handled by a DataSet object which manages these variables, but
+    // we can do it here for now.
+    x = 2;
+    y = 2;
+
+    // Before we can access these new values through our value chain, we need
+    // to tell the values to "reset". One of the main features of FV is that
+    // each value is only calculated at most once per observation, regardless
+    // of how many times it is accessed. However, this means that we have to
+    // tell the objects when a new object has been loaded so it will actually
+    // do a re-calculation. In the case of dp, this means that it will
+    // re-access the values of x and y and create a new pair with the updated
+    // values.
+    fv::GenValue::reset();
+
+    // Call print_pair again just to verify that it gives the updated values,
+    // and indeed it does.
+    // (2, 2)
+    print_pair(dp);
+
+    return 0;
+}

+ 74 - 0
examples/example2.cpp

@@ -0,0 +1,74 @@
+#include <iostream>
+#include <vector>
+#include <utility>
+
+#include "TFile.h"
+#include "TTree.h"
+#include "TCanvas.h"
+
+#include "filval/filval.hpp"
+
+#include "MiniTreeDataSet.hpp"
+
+void test2(){
+    double x = 12;
+    ObservedValue<double> x_val("x", &x);
+    ContainerTH1D hist("h1", "Hist", &x_val, 20, 0, 20);
+    hist.fill();
+    hist.fill();
+    hist.fill();
+    x = 11;
+    hist.fill();
+    hist.fill();
+    hist.fill();
+    hist.fill();
+    hist.fill();
+    hist.fill();
+
+    TH1D* h = (TH1D*) hist.get_container();
+    TCanvas can("c1");
+    h->Draw();
+    can.Draw();
+    can.SaveAs("outfile.png");
+}
+
+void test3(){
+    TFile *f = TFile::Open("./data/TTTT_ext_treeProducerSusyMultilepton_tree.root");
+    TTree *tree = (TTree*) f->Get("tree");
+    MiniTreeDataSet mtds(tree);
+    mtds.process();
+    TCanvas can("c1");
+    can.Clear();
+    TH1* hist = ((ContainerTH1I*)mtds.get_container("nLepGood"))->get_container();
+    hist->Draw();
+    can.Draw();
+    can.SaveAs("outfile.png");
+
+    can.Clear();
+    hist = ((ContainerTH1I*)mtds.get_container("nLepGood2"))->get_container();
+    hist->Draw();
+    can.Draw();
+    can.SaveAs("outfile2.png");
+
+    can.Clear();
+    hist = ((ContainerTH1I*)mtds.get_container("nLepGood3"))->get_container();
+    hist->Draw();
+    can.Draw();
+    can.SaveAs("outfile3.png");
+
+    can.Clear();
+    hist = ((ContainerTH1I*)mtds.get_container("avg_lepton_energy"))->get_container();
+    hist->Draw();
+    can.Draw();
+    can.SaveAs("lepton_energy.png");
+
+    can.Clear();
+    TGraph* graph= ((ContainerTGraph*)mtds.get_container("nLepvsnJet"))->get_container();
+    graph->Draw("A*");
+    can.Draw();
+    can.SaveAs("outfileGraph.png");
+
+    delete tree;
+    f->Close();
+    delete f;
+}

+ 52 - 0
examples/example3.cpp

@@ -0,0 +1,52 @@
+#include <iostream>
+#include <vector>
+#include <utility>
+
+#include "TFile.h"
+#include "TTree.h"
+#include "TCanvas.h"
+
+#include "filval/filval.hpp"
+
+#include "MiniTreeDataSet.hpp"
+
+void test3(){
+    TFile *f = TFile::Open("./data/TTTT_ext_treeProducerSusyMultilepton_tree.root");
+    TTree *tree = (TTree*) f->Get("tree");
+    MiniTreeDataSet mtds(tree);
+    mtds.process();
+    TCanvas can("c1");
+    can.Clear();
+    TH1* hist = ((ContainerTH1I*)mtds.get_container("nLepGood"))->get_container();
+    hist->Draw();
+    can.Draw();
+    can.SaveAs("outfile.png");
+
+    can.Clear();
+    hist = ((ContainerTH1I*)mtds.get_container("nLepGood2"))->get_container();
+    hist->Draw();
+    can.Draw();
+    can.SaveAs("outfile2.png");
+
+    can.Clear();
+    hist = ((ContainerTH1I*)mtds.get_container("nLepGood3"))->get_container();
+    hist->Draw();
+    can.Draw();
+    can.SaveAs("outfile3.png");
+
+    can.Clear();
+    hist = ((ContainerTH1I*)mtds.get_container("avg_lepton_energy"))->get_container();
+    hist->Draw();
+    can.Draw();
+    can.SaveAs("lepton_energy.png");
+
+    can.Clear();
+    TGraph* graph= ((ContainerTGraph*)mtds.get_container("nLepvsnJet"))->get_container();
+    graph->Draw("A*");
+    can.Draw();
+    can.SaveAs("outfileGraph.png");
+
+    delete tree;
+    f->Close();
+    delete f;
+}

+ 70 - 68
value.hpp

@@ -41,17 +41,18 @@
  */
 #ifndef value_hpp
 #define value_hpp
+#include <algorithm>
+#include <functional>
+#include <initializer_list>
 #include <iomanip>
 #include <iostream>
+#include <limits>
+#include <map>
 #include <sstream>
+#include <tuple>
+#include <typeindex>
 #include <utility>
-#include <algorithm>
-#include <map>
-#include <limits>
 #include <vector>
-#include <tuple>
-#include <initializer_list>
-#include <functional>
 
 #include "log.hpp"
 
@@ -88,13 +89,30 @@ namespace detail {
 }
 
 /**
- * Converts a std::vector to a std::tuple.
+ * Converts a std::array to a std::tuple.
  */
 template<typename T, std::size_t N, typename Indices = std::make_index_sequence<N>>
 decltype(auto) a2t(const std::array<T, N>& a){
     return detail::a2t_impl(a, Indices());
 }
 
+namespace detail {
+    // Convert tuple into a vector
+    template<typename R, typename Tuple, std::size_t... Is>
+    decltype(auto) t2v_impl(const Tuple& t, std::index_sequence<Is...>){
+        /* return std::make_tuple(a[I]...); */
+        return std::vector<R>({std::get<Is>(t)...});
+    }
+}
+
+/**
+ * Converts a std::tuple to a std::vector.
+ */
+template<typename R, typename... ArgTypes>
+std::vector<R> t2v(const std::tuple<ArgTypes...>& t){
+    return detail::t2v_impl<R, std::tuple<ArgTypes...>>(t, std::index_sequence_for<ArgTypes...>{});
+}
+
 namespace detail {
     template <class F, class Tuple, std::size_t... I>
     constexpr decltype(auto) call_impl(F &&f, Tuple &&t, std::index_sequence<I...>){
@@ -102,6 +120,9 @@ namespace detail {
     }
 }
 
+/**
+ * Call a function f with the elements of the tuple t as arguments
+ */
 template <class F, class Tuple>
 constexpr decltype(auto) call(F &&f, Tuple &&t){
     return detail::call_impl(
@@ -109,31 +130,6 @@ constexpr decltype(auto) call(F &&f, Tuple &&t){
         std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{});
 }
 
-namespace detail{
-    template <typename T, int N, int I>
-    struct t2s_impl{
-        public:
-            static std::string cvt(typename HomoTuple<T,N>::type& tup, std::function<std::string(T)>& f){
-                std::stringstream ss;
-                ss << f(std::get<N-I>(tup)) << ", " << t2s_impl<T, N, I+1>::cvt(tup, f);
-                return ss.str();
-            }
-    };
-
-    template <typename T, int N>
-    struct t2s_impl<T, N, 0>{
-        public:
-            static std::string cvt(typename HomoTuple<T,N>::type&, std::function<std::string(T)>&){
-                return "";
-            }
-    };
-}
-
-template <typename T, int N>
-std::string t2s(typename HomoTuple<T,N>::type& tup, std::function<std::string(T)>& f){
-    return detail::t2s_impl<T, N, N>(tup, f);
-}
-
 template<typename> class Function; // undefined
 
 /**
@@ -265,6 +261,8 @@ class Function<R(ArgTypes...)> : public GenFunction {
 
 #define FUNC(f) f, #f
 
+template <typename T>
+class Value;
 /**
  * A type-agnostic value.
  * It is necessary to create a type-agnostic parent class to Value so that
@@ -302,7 +300,7 @@ class GenValue{
          * creation of objects as well as avoiding the uneccesary passing of
          * pointers.
          */
-        inline static std::map<const std::string, GenValue*> values;
+        inline static std::map<std::pair<const std::type_index, const std::string>, GenValue*> values;
 
         /**
          * Composite value names are typically nested. This makes complex
@@ -311,30 +309,26 @@ class GenValue{
          * value is requested by name, an alias with that value takes precidence
          * over a name with that value.
          */
-        inline static std::map<const std::string, GenValue*> aliases;
+        inline static std::map<std::pair<const std::type_index, const std::string>, GenValue*> aliases;
 
         bool logging_enabled;
 
     public:
-        GenValue(const std::string& name, const std::string& alias)
-          :name(name),
-           value_valid(false),
-           logging_enabled(false){
-            INFO("Registered value: \"" << name << "\" with alias: \"" << alias << "\"");
-            values[name] = this;
+        GenValue(const std::type_index&& ti, const std::string& name, const std::string& alias)
+          :name(name), value_valid(false), logging_enabled(false){
             if (alias != "")
-                GenValue::alias(alias, this);
+                INFO("Registered value: \"" << name << "\" with alias: \"" << alias << "\"");
+            else
+                INFO("Registered value: \"" << name);
+            values[std::make_pair(ti,name)] = this;
+            if (alias != "")
+                GenValue::alias(ti, alias, this);
         }
 
         const std::string& get_name(){
             return name;
         }
 
-        void set_name(const std::string& new_name){
-            values[name] = nullptr;
-            name = new_name;
-            values[name] = this;
-        }
 
         /**
          * If logging is enabled for this value, this function should be
@@ -352,45 +346,53 @@ class GenValue{
             }
         }
 
-        static GenValue* get_value(const std::string& name){
-            if (aliases[name] != nullptr)
-                return aliases[name];
+        template<typename T>
+        static Value<T>* get_value(const std::string& name){
+            const std::type_index& ti = typeid(T);
+            auto lookup_id = std::make_pair(ti,name);
+            if (aliases[lookup_id] != nullptr)
+                return (Value<T>*)aliases[lookup_id];
             else
-                return values[name];
+                return (Value<T>*)values[lookup_id];
         }
 
-        static void alias(const std::string& name, GenValue* value){
-            if (aliases[name] != nullptr){
+
+        static void alias(const std::type_index& ti, const std::string& name, GenValue* value){
+            auto lookup_id = std::make_pair(ti,name);
+            if (aliases[lookup_id] != nullptr){
                 WARNING("WARNING: alias \"" << name << "\" overrides previous entry.");
             }
-            aliases[name] = value;
+            aliases[lookup_id] = value;
         }
 
-        static GenValue* alias(const std::string& name){
-            if (values[name] != nullptr){
-                WARNING("Alias \"" << name << "\" does not exist.");
-            }
-            return aliases[name];
+        template<typename T>
+        static void alias(const std::string& name, Value<T>* value){
+            alias(typeid(T), name, value);
         }
 
         static std::string summary(){
             std::stringstream ss;
             ss << "The following values have been created:" << std::endl;
-            for (auto value : values){
-                if (value.second == nullptr) continue;
-                ss << "\tVALUE::\"" << value.first << "\" at address " << value.second << std::endl;
+            for (auto item : values){
+                auto& key = item.first;
+                auto& value = item.second;
+                if (value == nullptr) continue;
+                ss << "\tVALUE::\"" << key.second << "\" at address " << value << std::endl;
             }
             ss << "And these aliases:" << std::endl;
-            for (auto alias : aliases){
+            for (auto item : aliases){
+                auto& key = item.first;
+                auto& value = item.second;
                 std::string orig("VOID");
-                if (alias.second == nullptr) continue;
-                for (auto value : values){
-                    if (alias.second == value.second){
-                        orig = value.second->get_name();
+                if (value == nullptr) continue;
+                for (auto v_item : values){
+                    auto& v_value = v_item.second;
+                    if (v_value == value){
+                        orig = v_value->get_name();
                         break;
                     }
                 }
-                ss << "\tALIAS::\"" << alias.first << "\" referring to \"" << orig << "\"" << std::endl;
+                ss << "\tALIAS::\"" << key.second << "\" referring to \"" << orig << "\"" << std::endl;
             }
             return ss.str();
         }
@@ -419,7 +421,7 @@ class Value : public GenValue{
     public:
         Value(const std::string& name, const std::string& alias="")
           :value_to_string([](T){return "";}),
-           GenValue(name, alias){ }
+           GenValue(typeid(T), name, alias){ }
         /** Calculate, if necessary, and return the value held by this object.
          */
         virtual T& get_value() = 0;