BCDataSet.cxx
1 /*
2  * Copyright (C) 2007-2018, the BAT core developer team
3  * All rights reserved.
4  *
5  * For the licensing terms see doc/COPYING.
6  * For documentation see http://mpp.mpg.de/bat
7  */
8 
9 // ---------------------------------------------------------
10 
11 #include "BCDataSet.h"
12 
13 #include "BCAux.h"
14 #include "BCDataPoint.h"
15 #include "BCLog.h"
16 
17 #include <TFile.h>
18 #include <TGraph.h>
19 #include <TGraphErrors.h>
20 #include <TGraphAsymmErrors.h>
21 #include <TH2D.h>
22 #include <TString.h>
23 #include <TTree.h>
24 
25 #include <cmath>
26 #include <fstream>
27 #include <limits>
28 #include <sstream>
29 
30 // ---------------------------------------------------------
32 {
34 }
35 
36 // ---------------------------------------------------------
37 std::vector<double> BCDataSet::GetDataComponents(unsigned index) const
38 {
39  std::vector<double> components;
40 
41  if (index >= fNValuesPerPoint)
42  return components;
43 
44  // reserve space
45  components.reserve(fDataVector.size());
46 
47  // loop over data points
48  for (unsigned i = 0; i < fDataVector.size(); ++i)
49  components.push_back(fDataVector[i][index]);
50 
51  return components;
52 }
53 
54 // ---------------------------------------------------------
56 {
57  for (unsigned i = 0; i < GetNValuesPerPoint(); ++i)
58  if (!std::isfinite(GetLowerBound(i)) || !std::isfinite(GetUpperBound(i)))
59  return false;
60  return true;
61 }
62 
63 // ---------------------------------------------------------
64 double BCDataSet::GetLowerBound(unsigned index) const
65 {
66  if (index > GetNValuesPerPoint()) {
67  BCLog::OutError("BCDataSet::GetLowerBound : index out of range.");
68  return std::numeric_limits<double>::infinity();
69  }
70  if (std::isfinite(fUserLowerBounds[index]))
71  return fUserLowerBounds[index];
72  return fLowerBounds[index];
73 }
74 
75 // ---------------------------------------------------------
76 double BCDataSet::GetUpperBound(unsigned index) const
77 {
78  if (index > GetNValuesPerPoint()) {
79  BCLog::OutError("BCDataSet::GetUpperBound : index out of range.");
80  return -std::numeric_limits<double>::infinity();
81  }
82  if (std::isfinite(fUserUpperBounds[index]))
83  return fUserUpperBounds[index];
84  return fUpperBounds[index];
85 }
86 
87 // ---------------------------------------------------------
88 bool BCDataSet::ReadDataFromFileTree(const std::string& filename, const std::string& treename, const std::string& branchnames, char delim)
89 {
90  // open root file
91  TFile* file = TFile::Open(filename.data(), "READ");
92 
93  // check if file is open and warn if not.
94  if (!file->IsOpen()) {
95  BCLog::OutError("BCDataSet::ReadDataFromFileTree : Could not open file " + filename + ".");
96  return false;
97  }
98 
99  // get tree
100  TTree* tree = (TTree*) file->Get(treename.data());
101 
102  // check if tree is there and warn if not.
103  if (!tree) {
104  BCLog::OutError("BCDataSet::ReadDataFromFileTree : Could not find TTree " + treename + ".");
105  file->Close();
106  return false;
107  }
108 
109  // calculate maximum number of entries
110  long nentries = tree->GetEntries();
111 
112  // check if there are any events in the tree and close file if not.
113  if (nentries <= 0) {
114  BCLog::OutError("BCDataSet::ReadDataFromFileTree : No events in TTree " + treename + ".");
115  file->Close();
116  return false;
117  }
118 
119  // if data set contains data, clear data object container ...
120  if (!fDataVector.empty()) {
121  Reset();
122  BCLog::OutDetail("BCDataSet::ReadDataFromFileTree : Overwrite existing data.");
123  }
124 
125  // define a vector of std::strings which contain the tree names.
126  std::vector<std::string> branches;
127  // split branchnames string up into above vector
128  std::stringstream branch_ss(branchnames);
129  std::string branchname;
130  while (std::getline(branch_ss, branchname, delim))
131  if (!branchname.empty())
132  branches.push_back(branchname);
133 
134  // create temporary vector with data and assign some zeros.
135  std::vector<double> data(branches.size(), 0);
136 
137  // set the branch address.
138  for (unsigned i = 0; i < branches.size(); ++i)
139  tree->SetBranchAddress(branches[i].data(), &data[i]);
140 
141  // loop over entries
142  for (long ientry = 0; ientry < nentries; ++ientry) {
143  tree->GetEntry(ientry);
144  AddDataPoint(BCDataPoint(data));
145  }
146 
147  file->Close();
148 
149  // remove file pointer.
150  if (file)
151  delete file;
152 
153  return true;
154 }
155 
156 // ---------------------------------------------------------
157 bool BCDataSet::ReadDataFromFileTxt(const std::string& filename, int nbranches)
158 {
159  // open text file.
160  std::fstream file;
161  file.open(filename.data(), std::fstream::in);
162 
163  // check if file is open and warn if not.
164  if (!file.is_open()) {
165  BCLog::OutError("BCDataSet::ReadDataFromFileText : Could not open file " + filename + ".");
166  return false;
167  }
168 
169  // if data set contains data, clear data object container ...
170  if (!fDataVector.empty()) {
171  Reset();
172  BCLog::OutDetail("BCDataSet::ReadDataFromFileTxt : Overwrite existing data.");
173  }
174 
175  // create temporary vector with data and assign some zeros.
176  std::vector<double> data(nbranches, 0);
177 
178  // reset counter
179  int nentries = 0;
180 
181  // read data and create data points.
182  while (!file.eof()) {
183 
184  // read data from file
185  int i = 0;
186  while (file >> data[i]) {
187  if (i == nbranches - 1)
188  break;
189  i++;
190  }
191 
192  // create data point.
193  if (i == nbranches - 1) {
194  AddDataPoint(BCDataPoint(data));
195  ++nentries;
196  }
197  }
198 
199  // issue error if no entries were loaded
200  if (nentries <= 0)
201  BCLog::OutError("BCDataSet::ReadDataFromFileText : No events in the file " + filename + ".");
202 
203  file.close();
204 
205  return (nentries > 0);
206 }
207 
208 // ---------------------------------------------------------
209 bool BCDataSet::AddDataPoint(const BCDataPoint& datapoint)
210 {
211  if (fNValuesPerPoint == 0 && fDataVector.empty())
212  SetNValuesPerPoint(datapoint.GetNValues());
213 
214  if (datapoint.GetNValues() != GetNValuesPerPoint())
215  return false;
216 
217  fDataVector.push_back(datapoint);
218 
219  for (unsigned i = 0; i < GetNValuesPerPoint(); ++i) {
220  // check lower bound
221  if (fDataVector.back()[i] < fLowerBounds[i])
222  fLowerBounds[i] = fDataVector.back()[i];
223  // check upper bound
224  if (fDataVector.back()[i] > fUpperBounds[i])
225  fUpperBounds[i] = fDataVector.back()[i];
226  }
227 
228  return true;
229 }
230 
231 // ---------------------------------------------------------
232 void BCDataSet::AdjustBoundForUncertainties(unsigned i, double nSigma, unsigned i_err1, int i_err2)
233 {
234  // check indices
235  if (i >= GetNValuesPerPoint() || i_err1 >= GetNValuesPerPoint() || i_err2 >= (int)GetNValuesPerPoint())
236  return;
237 
238  // if uncertainty above value is unassigned, use same data axis as for below.
239  if (i_err2 < 0)
240  i_err2 = i_err1;
241 
242  // recalculate bounds accounting for uncertainty
243  for (unsigned j = 0; j < fDataVector.size(); ++j) {
244 
245  // check lower bound
246  if (fDataVector[j][i] - nSigma * fDataVector[j][i_err1] < fLowerBounds[i])
247  fLowerBounds[i] = fDataVector[j][i] - nSigma * fDataVector[j][i_err1];
248 
249  // check upper bound
250  if (fDataVector[j][i] + nSigma * fDataVector[j][i_err2] > fUpperBounds[i])
251  fUpperBounds[i] = fDataVector[j][i] + nSigma * fDataVector[j][i_err2];
252  }
253 }
254 
255 // ---------------------------------------------------------
257 {
258  fNValuesPerPoint = n;
259  fLowerBounds.SetNValues(n, std::numeric_limits<double>::infinity());
260  fUpperBounds.SetNValues(n, -std::numeric_limits<double>::infinity());
261  fUserLowerBounds.SetNValues(n, std::numeric_limits<double>::infinity());
262  fUserUpperBounds.SetNValues(n, -std::numeric_limits<double>::infinity());
263  fFixed.assign(n, false);
264 }
265 
266 // ---------------------------------------------------------
267 void BCDataSet::SetBounds(unsigned index, double lower_bound, double upper_bound, bool fixed)
268 {
269  if (index >= GetNValuesPerPoint()) {
270  BCLog::OutError("BCDataSet::SetBounds : index out of range.");
271  return;
272  }
273  if (lower_bound >= upper_bound) {
274  BCLog::OutWarning("BCDataSet::SetBounds : lower bound is greater than or equal to upper_bound.");
275  return;
276  }
277  fUserLowerBounds[index] = lower_bound;
278  fUserUpperBounds[index] = upper_bound;
279  fFixed[index] = fixed;
280 }
281 
282 // ---------------------------------------------------------
283 void BCDataSet::PrintSummary(void (*output)(const std::string&)) const
284 {
285  output("Data set summary:");
286  output(Form("Number of points : %u", GetNDataPoints()));
287  output(Form("Number of values per point : %u", GetNValuesPerPoint()));
288  for (unsigned i = 0; i < fDataVector.size(); ++i) {
289  output(Form("Data point %5u", i));
290  fDataVector[i].PrintSummary(output);
291  }
292 }
293 
294 // ---------------------------------------------------------
295 TGraph* BCDataSet::GetGraph(unsigned x, unsigned y) const
296 {
297  if (x >= GetNValuesPerPoint() || y >= GetNValuesPerPoint())
298  return NULL;
299 
300  TGraph* G = new TGraph();
301 
302  // fill graph
303  for (unsigned i = 0; i < fDataVector.size(); ++i)
304  G->SetPoint(i, fDataVector[i][x], fDataVector[i][y]);
305 
306  return G;
307 }
308 
309 // ---------------------------------------------------------
310 TGraphErrors* BCDataSet::GetGraph(unsigned x, unsigned y, int ex, int ey) const
311 {
312  if (x >= GetNValuesPerPoint() || y >= GetNValuesPerPoint()
313  || ex >= (int)GetNValuesPerPoint() || ey >= (int)GetNValuesPerPoint())
314  return NULL;
315 
316  TGraphErrors* G = new TGraphErrors();
317 
318  // fill graph
319  for (unsigned i = 0; i < fDataVector.size(); ++i) {
320  G->SetPoint(i, fDataVector[i][x], fDataVector[i][y]);
321  double EX = (ex >= 0) ? fDataVector[i][ex] : 0;
322  double EY = (ey >= 0) ? fDataVector[i][ey] : 0;
323  G->SetPointError(i, EX, EY);
324  }
325 
326  return G;
327 }
328 
329 // ---------------------------------------------------------
330 TGraphAsymmErrors* BCDataSet::GetGraph(unsigned x, unsigned y, int ex_below, int ex_above, int ey_below, int ey_above) const
331 {
332  if (x >= GetNValuesPerPoint() || y >= GetNValuesPerPoint()
333  || ex_below >= (int)GetNValuesPerPoint() || ex_above >= (int)GetNValuesPerPoint()
334  || ey_below >= (int)GetNValuesPerPoint() || ey_above >= (int)GetNValuesPerPoint())
335  return NULL;
336 
337  TGraphAsymmErrors* G = new TGraphAsymmErrors();
338 
339  // fill graph
340  for (unsigned i = 0; i < fDataVector.size(); ++i) {
341  G->SetPoint(i, fDataVector[i][x], fDataVector[i][y]);
342  double EXb = (ex_below >= 0) ? fDataVector[i][ex_below] : 0;
343  double EXa = (ex_above >= 0) ? fDataVector[i][ex_above] : 0;
344  double EYb = (ey_below >= 0) ? fDataVector[i][ey_below] : 0;
345  double EYa = (ey_above >= 0) ? fDataVector[i][ey_above] : 0;
346  G->SetPointError(i, EXb, EXa, EYb, EYa);
347  }
348 
349  return G;
350 }
351 
352 // ---------------------------------------------------------
353 TH2* BCDataSet::CreateH2(const char* name, const char* title, unsigned x, unsigned y, unsigned nbins_x, unsigned nbins_y, double x_padding, double y_padding) const
354 {
355  if (x >= GetNValuesPerPoint() || y >= GetNValuesPerPoint())
356  return NULL;
357 
358  if (!BoundsExist())
359  return NULL;
360 
361  double x_low = GetLowerBound(x);
362  double x_high = GetUpperBound(x);
363  double y_low = GetLowerBound(y);
364  double y_high = GetUpperBound(y);
365 
366  if (x_padding > 0) {
367  double dX = x_padding * (x_high - x_low);
368  x_low -= dX;
369  x_high += dX;
370  }
371  if (y_padding > 0) {
372  double dY = y_padding * (y_high - y_low);
373  y_low -= dY;
374  y_high += dY;
375  }
376 
377  TH2* res;
378  {
380  res = new TH2D(name, title, nbins_x, x_low, x_high, nbins_y, y_low, y_high);
381  }
382  return res;
383 }
void SetBounds(unsigned index, double lower_bound, double upper_bound, bool fixed=false)
Set bounds for data values.
Definition: BCDataSet.cxx:267
bool AddDataPoint(const BCDataPoint &datapoint)
Adds a data point to the data set.
Definition: BCDataSet.cxx:209
bool ReadDataFromFileTxt(const std::string &filename, int nvariables)
Reads data from a .txt file.
Definition: BCDataSet.cxx:157
A class representing a data point.
Definition: BCDataPoint.h:34
void SetNValues(unsigned n, double val=0.)
Set the number of variables.
Definition: BCDataPoint.h:114
unsigned int GetNValues() const
Returns the number of values.
Definition: BCDataPoint.h:89
A guard object to prevent ROOT from taking over ownership of TNamed objects.
Definition: BCAux.h:171
std::vector< double > GetDataComponents(unsigned index) const
Viewing the data set as a table with one row per point, this method returns a specified column...
Definition: BCDataSet.cxx:37
bool ReadDataFromFileTree(const std::string &filename, const std::string &treename, const std::string &branchnames, char delim= ',')
Reads a TTree from a .root file.
Definition: BCDataSet.cxx:88
TH2 * CreateH2(const char *name, const char *title, unsigned x, unsigned y, unsigned nbins_x=100, unsigned nbins_y=100, double x_padding=0.10, double y_padding=0.10) const
Get ROOT TH2 with ranges set to data bounds.
Definition: BCDataSet.cxx:353
unsigned GetNDataPoints() const
Definition: BCDataSet.h:75
void SetNValuesPerPoint(unsigned n)
Set number of values inside each data point.
Definition: BCDataSet.cxx:256
double GetLowerBound(unsigned index) const
Return user-set lower bound on data, if set, otherwise actual lower bound.
Definition: BCDataSet.cxx:64
void Reset()
Resets the content of the data set.
Definition: BCDataSet.h:245
void AdjustBoundForUncertainties(unsigned i, double nSigma, unsigned i_err1, int i_err2=-1)
Recalculate a data axis bound accounting for uncertainties specified by other data axes...
Definition: BCDataSet.cxx:232
bool BoundsExist() const
Definition: BCDataSet.cxx:55
void PrintSummary(void(*output)(const std::string &)=BCLog::OutSummary) const
Print summary to string handler.
Definition: BCDataSet.cxx:283
BCDataSet(unsigned n=0)
Default constructor.
Definition: BCDataSet.cxx:31
double GetUpperBound(unsigned index) const
Return user-set upper bound on data, if set, otherwise actual upper bound.
Definition: BCDataSet.cxx:76
TGraph * GetGraph(unsigned x, unsigned y) const
Get data set as ROOT TGraph object,.
Definition: BCDataSet.cxx:295
unsigned GetNValuesPerPoint() const
Definition: BCDataSet.h:80