From 188b1dce64b84f844caeb6ec4d05c782f266b0a8 Mon Sep 17 00:00:00 2001
From: Danilo Piparo <danilo.piparo@cern.ch>
Date: Thu, 2 Mar 2017 14:50:22 +0100
Subject: [PATCH] [TDF] Add a Fill method to fill any object the class of which
 exposes a Fill method

---
 tree/treeplayer/inc/ROOT/TDataFrame.hxx    | 30 ++++++++++-
 tutorials/dataframe/tdf005_fillAnyObject.C | 63 ++++++++++++++++++++++
 2 files changed, 92 insertions(+), 1 deletion(-)
 create mode 100644 tutorials/dataframe/tdf005_fillAnyObject.C

diff --git a/tree/treeplayer/inc/ROOT/TDataFrame.hxx b/tree/treeplayer/inc/ROOT/TDataFrame.hxx
index 622ec31fb1e..e9659e889bf 100644
--- a/tree/treeplayer/inc/ROOT/TDataFrame.hxx
+++ b/tree/treeplayer/inc/ROOT/TDataFrame.hxx
@@ -795,7 +795,6 @@ public:
       return df->MakeActionResultProxy(h);
    }
 
-
    ////////////////////////////////////////////////////////////////////////////
    /// \brief Fill and return a profile (*lazy action*)
    /// \tparam B0 The type of the branch the values of which are used to fill the profile.
@@ -916,6 +915,35 @@ public:
       return df->MakeActionResultProxy(h);
    }
 
+
+   ////////////////////////////////////////////////////////////////////////////
+   /// \brief Fill and return any entity with a Fill method (*lazy action*)
+   /// \tparam BRANCHTYPES The types of the branches the values of which are used to fill the object.
+   /// \param[in] model The model to be considered to build the new return value.
+   /// \param[in] bl The name of the branches read to fill the object.
+   ///
+   /// The returned object is independent of the input one.
+   /// This action is *lazy*: upon invocation of this method the calculation is
+   /// booked but not executed. See TActionResultProxy documentation.
+   /// The user renounces to the ownership of the model. The value to be used is the
+   /// returned one.
+   /// It is compulsory to express the branches to be considered.
+   template <typename... BRANCHTYPES, typename T>
+   TActionResultProxy<T> Fill(T &&model, const BranchNames& bl)
+   {
+      auto h = std::make_shared<T>(model);
+      if (!ROOT::Internal::TDFV7Utils::Histo<T>::HasAxisLimits(*h)) {
+         throw std::runtime_error("The absence of axes limits is not supported yet.");
+      }
+      using Op_t = ROOT::Internal::Operations::FillTOOperation<T>;
+      using DFA_t = ROOT::Internal::TDataFrameAction<Op_t, Proxied, ROOT::Internal::TDFTraitsUtils::TTypeList<BRANCHTYPES...>>;
+      auto df = GetDataFrameChecked();
+      auto nSlots = df->GetNSlots();
+      df->Book(std::make_shared<DFA_t>(Op_t(h, nSlots), bl, *fProxiedPtr));
+      return df->MakeActionResultProxy(h);
+   }
+
+
    ////////////////////////////////////////////////////////////////////////////
    /// \brief Return the minimum of processed branch values (*lazy action*)
    /// \tparam T The type of the branch.
diff --git a/tutorials/dataframe/tdf005_fillAnyObject.C b/tutorials/dataframe/tdf005_fillAnyObject.C
new file mode 100644
index 00000000000..b54cfb753b1
--- /dev/null
+++ b/tutorials/dataframe/tdf005_fillAnyObject.C
@@ -0,0 +1,63 @@
+/// \file
+/// \ingroup tutorial_tdataframe
+/// \notebook -nodraw
+/// This tutorial shows how to fill any object the class of which exposes a
+/// `Fill` method.
+/// \macro_code
+///
+/// \date March 2017
+/// \author Danilo Piparo
+
+#include "TFile.h"
+#include "TH1F.h"
+#include "TTree.h"
+
+#include "ROOT/TDataFrame.hxx"
+
+// A simple helper function to fill a test tree: this makes the example
+// stand-alone.
+void fill_tree(const char* filename, const char* treeName) {
+   TFile f(filename,"RECREATE");
+   TTree t(treeName,treeName);
+   double b1;
+   float b2;
+   t.Branch("b1", &b1);
+   t.Branch("b2", &b2);
+   for(int i = 0; i < 100; ++i) {
+      b1 = i;
+      b2 = i*i;
+      t.Fill();
+   }
+   t.Write();
+   f.Close();
+   return;
+}
+
+int tdf005_fillAnyObject() {
+
+   // We prepare an input tree to run on
+   auto fileName = "tdf005_fillAnyObject.root";
+   auto treeName = "myTree";
+   fill_tree(fileName,treeName);
+
+   // We read the tree from the file and create a TDataFrame.
+   ROOT::Experimental::TDataFrame d(treeName, fileName);
+
+   // ## Filling any object
+   // We now fill some objects which are instances of classes which expose a
+   // `Fill` method with some input arguments.
+   auto th1d = d.Fill<double>(TH1D("th1d", "th1d", 64, 0, 128), {"b1"});
+   auto th1i = d.Fill<float>(TH1I("th1i", "th1i", 64, 0, 128), {"b2"});
+   auto th2d = d.Fill<double, float>(TH2D("th2d", "th2d", 64, 0, 128, 64, 0, 1024), {"b1","b2"});
+
+   auto c1 = new TCanvas();
+   th1d->DrawClone();
+
+   auto c2 = new TCanvas();
+   th1i->DrawClone();
+
+   auto c3 = new TCanvas();
+   th2d->DrawClone("COLZ");
+
+   return 0;
+}
-- 
GitLab