Belle II Software  release-08-01-10
calibTools.h
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 
10 
11 #pragma once
12 
13 #include <tracking/calibration/Splitter.h>
14 #include <TMatrixDSym.h>
15 #include <functional>
16 #include <map>
17 
18 #include <framework/database/EventDependency.h>
19 #include <framework/datastore/StoreArray.h>
20 #include <framework/geometry/B2Vector3.h>
21 #include <calibration/CalibrationAlgorithm.h>
22 
23 #include <Eigen/Dense>
24 
25 namespace Belle2 {
31  // General functions to perform the calibration
32  // Notice that the goal of the calibration is to estimate the parameters
33  // of the Gaussian distribution: center + covariance matrix describing the spread.
34  // In general it requires more data to determine the spread, so there can be
35  // several calib. subintervals with different values of
36  // the center position of the Gaussian (mean) but with identical spread parameters.
37  // The longer intervals of constant spread are called "intervals"
38  // The shorter intervals of constant mean value are called "subintervals"
39  // In general there are several subintervals withing single interval
40  // By definition a subinterval always belongs only to single interval.
41 
42 
44  inline TMatrixDSym toTMatrixDSym(Eigen::MatrixXd mIn)
45  {
46  TMatrixDSym mOut(mIn.rows());
47  for (int i = 0; i < mIn.rows(); ++i)
48  for (int j = 0; j < mIn.cols(); ++j)
49  mOut(i, j) = (mIn(i, j) + mIn(j, i)) / 2.;
50  return mOut;
51  }
52 
54  inline B2Vector3D toB2Vector3(Eigen::VectorXd vIn)
55  {
56  return B2Vector3D(vIn(0), vIn(1), vIn(2));
57  }
58 
60  inline int getID(const std::vector<double>& breaks, double t)
61  {
62  for (int i = 0; i < int(breaks.size()) + 1; ++i) {
63  double s = (i == 0) ? 0 : breaks[i - 1];
64  double e = (i == int(breaks.size())) ? 1e20 : breaks[i];
65  if (s <= t && t < e)
66  return i;
67  }
68  return -1;
69  }
70 
72  struct CalibPars {
73  std::vector<Eigen::VectorXd> cnt;
74  std::vector<Eigen::MatrixXd> cntUnc;
75  Eigen::MatrixXd spreadMat;
76 
77  double spreadUnc = std::numeric_limits<double>::quiet_NaN();
78  double shift =
79  std::numeric_limits<double>::quiet_NaN();
80  double shiftUnc = std::numeric_limits<double>::quiet_NaN();
81  std::vector<double> pulls;
82  int size() const {return cnt.size();}
83  };
84 
85 
87  struct CalibrationData {
89  std::vector<std::map<ExpRun, std::pair<double, double>>> subIntervals;
90 
91  std::vector<ExpRunEvt> breakPoints;
92 
94 
95  bool isCalibrated = false;
96 
97  };
98 
99 
100 
102  inline void extrapolateCalibration(std::vector<CalibrationData>& calVec)
103  {
104  //put closest neighbor, where the statistic was low or algo failed
105  for (unsigned i = 0; i < calVec.size(); ++i) {
106  if (calVec[i].pars.cnt.size() != 0) continue;
107  const auto& r = calVec[i].subIntervals;
108  double Start, End;
109  std::tie(Start, End) = Splitter::getStartEnd(r);
110 
111  Eigen::Vector3d ipNow;
112  Eigen::MatrixXd ipeNow;
113  Eigen::MatrixXd sizeMatNow;
114 
115  double distMin = 1e20;
116  //Find the closest calibrated interval
117  for (unsigned j = 0; j < calVec.size(); ++j) {
118  if (calVec[j].isCalibrated == false) continue; //skip not-calibrated intervals
119  const auto& rJ = calVec[j].subIntervals;
120  for (unsigned jj = 0; jj < rJ.size(); ++jj) { //loop over subintervals
121  const auto& rNow = rJ[jj];
122  double s = rNow.begin()->second.first;
123  double e = rNow.rbegin()->second.second;
124 
125  double dist1 = (s - End >= 0) ? (s - End) : 1e20;
126  double dist2 = (Start - e >= 0) ? (Start - e) : 1e20;
127  double dist = std::min(dist1, dist2);
128 
129  if (dist < distMin) {
130  ipNow = calVec[j].pars.cnt.at(jj);
131  ipeNow = calVec[j].pars.cntUnc.at(jj);
132  sizeMatNow = calVec[j].pars.spreadMat;
133  distMin = dist;
134  }
135  }
136  }
137 
138  //Store it to vectors
139  calVec[i].pars.cnt.resize(r.size());
140  calVec[i].pars.cntUnc.resize(r.size());
141  for (unsigned ii = 0; ii < r.size(); ++ii) {
142  calVec[i].pars.cnt.at(ii) = ipNow;
143  calVec[i].pars.cntUnc.at(ii) = ipeNow;
144  }
145  calVec[i].pars.spreadMat = sizeMatNow;
146  }
147 
148  }
149 
151  inline void addShortRun(std::vector<CalibrationData>& calVec, std::pair<ExpRun, std::pair<double, double>> shortRun)
152  {
153  double shortStart = shortRun.second.first;
154  double shortEnd = shortRun.second.second;
155 
156  double distMin = 1e20;
157  int iMin = -1, jMin = -1;
158 
159  for (unsigned i = 0; i < calVec.size(); ++i) {
160  if (calVec[i].isCalibrated == false)
161  continue;
162  for (unsigned j = 0; j < calVec[i].subIntervals.size(); ++j) {
163  for (auto I : calVec[i].subIntervals[j]) {
164  double s = I.second.first;
165  double e = I.second.second;
166 
167  double dist1 = (s - shortEnd >= 0) ? (s - shortEnd) : 1e20;
168  double dist2 = (shortStart - e >= 0) ? (shortStart - e) : 1e20;
169  double dist = std::min(dist1, dist2);
170 
171  if (dist < distMin) {
172  distMin = dist;
173  iMin = i;
174  jMin = j;
175  }
176  }
177  }
178  }
179 
180  B2ASSERT("Must be found", iMin != -1 && jMin != -1);
181  calVec[iMin].subIntervals[jMin].insert(shortRun);
182  }
183 
186  inline double encodeNumber(double val, unsigned num)
187  {
188  double factor = pow(FLT_RADIX, DBL_MANT_DIG);
189  static const long long fEnc = pow(2, 32); //32 binary digits for encoded number
190 
191  int e; //exponent of the number
192  double mantisa = std::frexp(val, &e);
193  long long mantisaI = mantisa * factor; //mantissa as integer
194 
195  if (val != 0)
196  mantisaI = (mantisaI / fEnc) * fEnc + num; //adding encoded number to last digits of mantissa
197  else {
198  mantisaI = factor / 2 + num;
199  e = -100; //if the val is zero, ensure very small number by the exponent
200  }
201 
202  double newVal = ldexp(mantisaI / factor, e);
203 
204  return newVal;
205  }
206 
208  inline unsigned decodeNumber(double val)
209  {
210  double factor = pow(FLT_RADIX, DBL_MANT_DIG);
211  static const long long fEnc = pow(2, 32); //32 binary digits for encoded number
212 
213  int e;
214  double mantisa = std::frexp(val, &e);
215  long long mantisaI = mantisa * factor;
216 
217  return (mantisaI % fEnc);
218  }
219 
220 
221 
222 
224  template<typename Evt>
225  inline void storePayloads(const std::vector<Evt>& evts, const std::vector<CalibrationData>& calVecConst, std::string objName,
226  std::function<TObject*(Eigen::VectorXd, Eigen::MatrixXd, Eigen::MatrixXd) > getCalibObj)
227  {
228  auto calVec = calVecConst;
229 
230  // Loop to store payloads
231  ExpRun exprunLast(-1, -1); //last exprun
232  EventDependency* intraRun = nullptr;
233 
234  // Loop over calibration intervals
235  for (unsigned i = 0; i < calVec.size(); ++i) {
236  const auto& r = calVec[i].subIntervals; // splits[i];
237  // Loop over calibration subintervals
238  for (int k = 0; k < int(r.size()); ++k) {
239 
240  for (auto I : r[k]) { //interval required to be within single run
241  ExpRun exprun = I.first;
242 
243  //Encode Start+End time in seconds of the payload
244  if (calVec[i].pars.cntUnc.at(k).rows() == 3) {
245  calVec[i].pars.cntUnc.at(k)(0, 1) = calVec[i].pars.cntUnc.at(k)(1, 0) = encodeNumber(calVec[i].pars.cntUnc.at(k)(0, 1),
246  round(I.second.first * 3600));
247  calVec[i].pars.cntUnc.at(k)(0, 2) = calVec[i].pars.cntUnc.at(k)(2, 0) = encodeNumber(calVec[i].pars.cntUnc.at(k)(0, 2),
248  round(I.second.second * 3600));
249  } else {
250  calVec[i].pars.cntUnc.at(k)(0, 0) = encodeNumber(calVec[i].pars.cntUnc.at(k)(0, 0), round(I.second.first * 3600));
251  calVec[i].pars.spreadMat(0, 0) = encodeNumber(calVec[i].pars.spreadMat(0, 0), round(I.second.second * 3600));
252  }
253 
254  TObject* obj = getCalibObj(calVec[i].pars.cnt.at(k), calVec[i].pars.cntUnc.at(k), calVec[i].pars.spreadMat);
255  if (exprun != exprunLast) { //if new run
256  if (intraRun) { //if not first -> store
257  auto m_iov = IntervalOfValidity(exprunLast.exp, exprunLast.run, exprunLast.exp, exprunLast.run);
258  Database::Instance().storeData(objName, intraRun, m_iov);
259  }
260 
261  intraRun = new EventDependency(obj);
262  } else {
263  int breakPoint;
264  if (k - 1 >= 0) {
265  breakPoint = calVec[i].breakPoints.at(k - 1).evt;
266  B2ASSERT("Payload saving consistency", calVec[i].breakPoints.at(k - 1).run == exprun.run);
267  } else {
268  B2ASSERT("Payload saving consistency", i != 0);
269  double rStart, rEnd;
270  std::tie(rStart, rEnd) = Splitter::getStartEnd(r);
271  auto pos = getPosition(evts, rStart);
272  breakPoint = pos.evt;
273  B2ASSERT("Payload saving consistency", pos.run == exprun.run);
274  }
275  intraRun->add(breakPoint, obj);
276  }
277  exprunLast = exprun;
278  }
279  } //end loop over calibration subintervals
280 
281  } //end loop over calibration intervals
282 
283  //Store the last entry
284  auto m_iov = IntervalOfValidity(exprunLast.exp, exprunLast.run, exprunLast.exp, exprunLast.run);
285  Database::Instance().storeData(objName, intraRun, m_iov);
286  }
287 
288 
290  inline void storePayloadsNoIntraRun(const std::vector<CalibrationData>& calVecConst, std::string objName,
291  std::function<TObject*(Eigen::VectorXd, Eigen::MatrixXd, Eigen::MatrixXd) > getCalibObj)
292  {
293  auto calVec = calVecConst;
294 
295  // Check that there is no intra-run dependence
296  std::set<ExpRun> existingRuns;
297  for (unsigned i = 0; i < calVec.size(); ++i) {
298  const auto& r = calVec[i].subIntervals;
299  // Loop over calibration subintervals
300  for (int k = 0; k < int(r.size()); ++k) {
301 
302  for (auto I : r[k]) {
303  ExpRun exprun = I.first;
304  // make sure that the run isn't already in the list, to avoid duplicity
305  if (existingRuns.count(exprun) != 0)
306  B2FATAL("Intra-run dependence exists");
307  existingRuns.insert(exprun);
308  }
309  }
310  }
311 
312 
313  // Loop over calibration intervals
314  for (unsigned i = 0; i < calVec.size(); ++i) {
315  const auto& r = calVec[i].subIntervals; // splits[i];
316  // Loop over calibration subintervals
317  for (unsigned k = 0; k < r.size(); ++k) {
318 
319  TObject* obj = getCalibObj(calVec[i].pars.cnt.at(k), calVec[i].pars.cntUnc.at(k), calVec[i].pars.spreadMat);
320 
321  ExpRun start = (r[k].cbegin()->first);
322  ExpRun last = (r[k].crbegin()->first);
323 
324  auto iov = IntervalOfValidity(start.exp, start.run, last.exp, last.run);
325  Database::Instance().storeData(objName, obj, iov);
326 
327 
328  } //end loop over calibration subintervals
329  } //end loop over calibration intervals
330 
331  }
332 
334  template<typename Evt, typename Fun>
335  inline CalibrationData runAlgorithm(const std::vector<Evt>& evts, std::vector<std::map<ExpRun, std::pair<double, double>>> range,
336  Fun runCalibAnalysis
337  )
338  {
339  CalibrationData calD;
340  auto& r = range;
341  double rStart, rEnd;
342  std::tie(rStart, rEnd) = Splitter::getStartEnd(r);
343  B2INFO("Start of loop startTime endTime : " << rStart << " " << rEnd);
344 
345  auto breaks = Splitter::getBreaks(r);
346 
347  std::vector<Evt> evtsNow;
348 
349  std::vector<int> Counts(breaks.size() + 1, 0);
350  // Select events belonging to the interval
351  for (const auto& ev : evts) {
352  if (rStart <= ev.t && ev.t < rEnd) {
353  evtsNow.push_back(ev);
354  ++Counts.at(getID(breaks, ev.t));
355  }
356  }
357 
358  B2ASSERT("Number of intervals vs number of breakPoints", r.size() == breaks.size() + 1);
359 
360  //Merge smallest interval if with low stat (try it 10times)
361  for (int k = 0; k < 10; ++k) {
362  int iMin = min_element(Counts.begin(), Counts.end()) - Counts.begin();
363  if (Counts.size() >= 2 && Counts[iMin] < 50) { //merge with neighbor if possible
364  auto iM = -1;
365  if (iMin == 0)
366  iM = iMin + 1;
367  else if (iMin == int(Counts.size()) - 1)
368  iM = iMin - 1;
369  else {
370  if (Counts[iMin + 1] < Counts[iMin - 1])
371  iM = iMin + 1;
372  else
373  iM = iMin - 1;
374  }
375  B2ASSERT("Number of intervals equal to size of counters", r.size() == Counts.size());
376 
377  r.at(iM) = Splitter::mergeIntervals(r[iM], r[iMin]);
378  r.erase(r.begin() + iMin);
379  breaks = Splitter::getBreaks(r);
380  Counts[iM] += Counts[iMin];
381  Counts.erase(Counts.begin() + iMin);
382  }
383  }
384 
385  B2INFO("#events " << " : " << evtsNow.size());
386  B2INFO("Breaks size " << " : " << breaks.size());
387 
388  calD.breakPoints = convertSplitPoints(evtsNow, breaks);
389 
390  calD.subIntervals = r;
391 
392  if (breaks.size() > 0)
393  B2INFO("StartOfCalibInterval (run,evtNo,vtxIntervalsSize) " << calD.breakPoints.at(0).run << " " <<
394  calD.breakPoints.at(0).evt << " " << calD.breakPoints.size());
395 
396 
397  //If too few events, let have the output empty
398  //Will be filled with the closest neighbor at the next stage
399  if (evtsNow.size() < 50) {
400  return calD;
401  }
402 
403  // Run the calibration
404  B2INFO("Start of running calibration over calibration interval");
405  tie(calD.pars.cnt, calD.pars.cntUnc, calD.pars.spreadMat) = runCalibAnalysis(evtsNow, breaks);
406  calD.pars.pulls.resize(calD.pars.cnt.size());
407  B2INFO("End of running analysis - SpreadMatX : " << sqrt(abs(calD.pars.spreadMat(0, 0))));
408  B2ASSERT("All subintervals have calibration of the mean value", calD.pars.cnt.size() == r.size());
409  B2ASSERT("All subintervals have calibration of the unc. of mean", calD.pars.cntUnc.size() == r.size());
410 
411  calD.isCalibrated = true;
412 
413  return calD;
414  }
415 
416 
427  template<typename Fun1, typename Fun2>
428  CalibrationAlgorithm::EResult runCalibration(TTree* tracks, const std::string& calibName, Fun1 GetEvents, Fun2 calibAnalysis,
429  std::function<TObject*(Eigen::VectorXd, Eigen::MatrixXd, Eigen::MatrixXd)> calibObjCreator,
430  TString m_lossFunctionOuter, TString m_lossFunctionInner)
431  {
432  // Check that there are at least some data
433  if (!tracks || tracks->GetEntries() < 15) {
434  if (tracks)
435  B2WARNING("Too few data : " << tracks->GetEntries());
436  return CalibrationAlgorithm::EResult::c_NotEnoughData;
437  }
438  B2INFO("Number of tracks: " << tracks->GetEntries());
439 
440  // Tree to vector of Events
441  auto evts = GetEvents(tracks);
442 
443  //Time range for each ExpRun
444  std::map<ExpRun, std::pair<double, double>> runsInfoOrg = getRunInfo(evts);
445  std::map<ExpRun, std::pair<double, double>> runsRemoved; //map with time intervals of very short runs
446  auto runsInfo = filter(runsInfoOrg, 2. / 60, runsRemoved); //include only runs longer than 2mins
447 
448  // If nothing remains
449  if (runsInfo.size() == 0) {
450  B2WARNING("Too short run");
451  return CalibrationAlgorithm::EResult::c_NotEnoughData;
452  }
453 
454  // Get intervals based on the input loss functions
455  Splitter splt;
456  auto splits = splt.getIntervals(runsInfo, evts, m_lossFunctionOuter, m_lossFunctionInner);
457 
458  //Loop over all calibration intervals
459  std::vector<CalibrationData> calVec;
460  for (auto s : splits) {
461  CalibrationData calD = runAlgorithm(evts, s, calibAnalysis); // run the calibration over the interval s
462  calVec.push_back(calD);
463  }
464 
465  // extrapolate results to the low-stat intervals
466  extrapolateCalibration(calVec);
467 
468  // Include removed short runs
469  for (auto shortRun : runsRemoved) {
470  addShortRun(calVec, shortRun);
471  }
472 
473  // Store Payloads to files
474  storePayloads(evts, calVec, calibName, calibObjCreator);
475 
476  return CalibrationAlgorithm::EResult::c_OK;
477  }
478 
479 
481 }
EResult
The result of calibration.
Class for handling changing conditions as a function of event number.
void add(unsigned int event, TObject *object)
Add an object to the intra run dependency.
A class that describes the interval of experiments/runs for which an object in the database is valid.
Class that allows to split runs into the intervals of intended properties given by the lossFunction.
Definition: Splitter.h:108
std::vector< std::vector< std::map< ExpRun, std::pair< double, double > > > > getIntervals(const std::map< ExpRun, std::pair< double, double >> &runs, std::vector< Evt > evts, TString lossFunctionOuter, TString lossFunctionInner, double atomSize=3./60)
Function to merge/divide runs into the calibration intervals of given characteristic length.
Definition: Splitter.h:163
static std::vector< double > getBreaks(std::vector< std::map< ExpRun, std::pair< double, double >>> res)
Get vector with breaks of the calib.
Definition: Splitter.h:131
static std::pair< double, double > getStartEnd(std::vector< std::map< ExpRun, std::pair< double, double >>> res)
Get the start/end time of the calibration interval (vector of the calib.
Definition: Splitter.h:120
static Database & Instance()
Instance of a singleton Database.
Definition: Database.cc:42
bool storeData(const std::string &name, TObject *object, const IntervalOfValidity &iov)
Store an object in the database.
Definition: Database.cc:141
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:516
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
ExpRunEvt getPosition(const std::vector< Evt > &events, double tEdge)
Get the exp-run-evt number from the event time [hours].
Definition: Splitter.h:341
void storePayloadsNoIntraRun(const std::vector< CalibrationData > &calVecConst, std::string objName, std::function< TObject *(Eigen::VectorXd, Eigen::MatrixXd, Eigen::MatrixXd) > getCalibObj)
Store payloads to files, where calib data have no intra-run dependence.
Definition: calibTools.h:290
void addShortRun(std::vector< CalibrationData > &calVec, std::pair< ExpRun, std::pair< double, double >> shortRun)
Extrapolate calibration to the very short runs which were filtered before.
Definition: calibTools.h:151
B2Vector3D toB2Vector3(Eigen::VectorXd vIn)
Function that converts Eigen vector to ROOT vector.
Definition: calibTools.h:54
unsigned decodeNumber(double val)
Decode the integer number encoded in val.
Definition: calibTools.h:208
double encodeNumber(double val, unsigned num)
Encode integer num into double val such that val is nearly not changed (maximally by a relative shift...
Definition: calibTools.h:186
std::map< ExpRun, std::pair< double, double > > filter(const std::map< ExpRun, std::pair< double, double >> &runs, double cut, std::map< ExpRun, std::pair< double, double >> &runsRemoved)
filter events to remove runs shorter than cut, it stores removed runs in runsRemoved
Definition: Splitter.cc:38
int getID(const std::vector< double > &breaks, double t)
get id of the time point t
Definition: calibTools.h:60
CalibrationData runAlgorithm(const std::vector< Evt > &evts, std::vector< std::map< ExpRun, std::pair< double, double >>> range, Fun runCalibAnalysis)
run calibration algorithm for single calibration interval
Definition: calibTools.h:335
TMatrixDSym toTMatrixDSym(Eigen::MatrixXd mIn)
Function that converts Eigen symmetric matrix to ROOT matrix.
Definition: calibTools.h:44
CalibrationAlgorithm::EResult runCalibration(TTree *tracks, const std::string &calibName, Fun1 GetEvents, Fun2 calibAnalysis, std::function< TObject *(Eigen::VectorXd, Eigen::MatrixXd, Eigen::MatrixXd)> calibObjCreator, TString m_lossFunctionOuter, TString m_lossFunctionInner)
Run the the calibration over the whole event sample.
Definition: calibTools.h:428
void extrapolateCalibration(std::vector< CalibrationData > &calVec)
Extrapolate calibration to intervals where it failed.
Definition: calibTools.h:102
void storePayloads(const std::vector< Evt > &evts, const std::vector< CalibrationData > &calVecConst, std::string objName, std::function< TObject *(Eigen::VectorXd, Eigen::MatrixXd, Eigen::MatrixXd) > getCalibObj)
Store payloads to files.
Definition: calibTools.h:225
std::map< ExpRun, std::pair< double, double > > getRunInfo(const std::vector< Evt > &evts)
Get the map of runs, where each run contains pair with start/end time [hours].
Definition: Splitter.h:312
std::vector< ExpRunEvt > convertSplitPoints(const std::vector< Evt > &events, std::vector< double > splitPoints)
Convert splitPoints [hours] to breakPoints in ExpRunEvt.
Definition: Splitter.h:363
static std::map< ExpRun, std::pair< double, double > > mergeIntervals(std::map< ExpRun, std::pair< double, double >> I1, std::map< ExpRun, std::pair< double, double >> I2)
Merge two subintervals into one subinterval.
Definition: Splitter.cc:306
Abstract base class for different kinds of events.
The parameters related to single calibration interval.
Definition: calibTools.h:72
std::vector< Eigen::MatrixXd > cntUnc
vector of uncertainties of means for each calib. subinterval
Definition: calibTools.h:74
std::vector< double > pulls
vector of pulls between mumu and hadB methods (for eCMS)
Definition: calibTools.h:81
Eigen::MatrixXd spreadMat
spread CovMatrix
Definition: calibTools.h:75
double shift
difference between eCMS for hadronic B decay method and mumu method, i.e. hadB - mumu
Definition: calibTools.h:78
std::vector< Eigen::VectorXd > cnt
vector of means for each calib. subinterval
Definition: calibTools.h:73
double shiftUnc
stat uncertainty of the shift
Definition: calibTools.h:80
int size() const
number of the subintervals
Definition: calibTools.h:82
double spreadUnc
stat uncertainty of the spread (for eCMS)
Definition: calibTools.h:77
Parameters and data relevant for single calibration interval.
Definition: calibTools.h:87
std::vector< std::map< ExpRun, std::pair< double, double > > > subIntervals
vector of the start and end times of the calibration subintervals
Definition: calibTools.h:89
CalibPars pars
The parameters of the calibration itself.
Definition: calibTools.h:93
bool isCalibrated
true if calibration run was successful
Definition: calibTools.h:95
std::vector< ExpRunEvt > breakPoints
vector with break points positions
Definition: calibTools.h:91
Struct containing exp number and run number.
Definition: Splitter.h:51
int exp
experiment number
Definition: Splitter.h:52
int run
run number
Definition: Splitter.h:53