MaCh3  2.5.1
Reference Guide
BinnedSplineHandler.cpp
Go to the documentation of this file.
1 #include "BinnedSplineHandler.h"
2 #include <memory>
3 
4 #pragma GCC diagnostic ignored "-Wuseless-cast"
5 #pragma GCC diagnostic ignored "-Wfloat-conversion"
6 
8 #include "TROOT.h"
9 #include "TKey.h"
10 #include "TH3F.h"
12 
13 //****************************************
15 //****************************************
16  if (!ParHandler_) {
17  MACH3LOG_ERROR("Trying to create BinnedSplineHandler with uninitialized covariance object");
18  throw MaCh3Exception(__FILE__, __LINE__);
19  }
20  ParHandler = ParHandler_;
21 
22  if (!Modes_) {
23  MACH3LOG_ERROR("Trying to create BinnedSplineHandler with uninitialized MaCh3Modes object");
24  throw MaCh3Exception(__FILE__, __LINE__);
25  }
26  Modes = Modes_;
27 
28  // Keep these in class scope, important for using 1 monolith/sample!
29  MonolithIndex = 0; //Keeps track of the monolith index we're on when filling arrays (declared here so we can have multiple FillSampleArray calls)
30  CoeffIndex = 0; //Keeps track of our indexing the coefficient arrays [x, ybcd]
31  isflatarray = nullptr;
32 }
33 
34 //****************************************
36 //****************************************
37  if(manycoeff_arr != nullptr) delete[] manycoeff_arr;
38  if(xcoeff_arr != nullptr) delete[] xcoeff_arr;
39  if(SplineSegments != nullptr) delete[] SplineSegments;
40  if(ParamValues != nullptr) delete[] ParamValues;
41 }
42 //****************************************
44 //****************************************
45  //Call once everything's been allocated in SampleHandlerFDBase, cleans up junk from memory!
46  //Not a huge saving but it's better than leaving everything up to the compiler
47  MACH3LOG_INFO("Cleaning up spline memory");
63  if(isflatarray) delete [] isflatarray;
64 }
65 
66 //****************************************
67 //Adds samples to the large array
68 void BinnedSplineHandler::AddSample(const std::string& SampleName,
69  const std::string& SampleTitle,
70  const std::vector<std::string>& OscChanFileNames,
71  const std::vector<std::string>& SplineVarNames) {
72 //****************************************
73  SampleNames.push_back(SampleName);
74  SampleTitles.push_back(SampleTitle);
75  Dimensions.push_back(static_cast<int>(SplineVarNames.size()));
76  DimensionLabels.push_back(SplineVarNames);
77 
78  int nSplineParam = ParHandler->GetNumParamsFromSampleName(SampleName, SystType::kSpline);
79  nSplineParams.push_back(nSplineParam);
80 
81  //This holds the global index of the spline i.e. 0 -> _fNumPar
82  std::vector<int> GlobalSystIndex_Sample = ParHandler->GetGlobalSystIndexFromSampleName(SampleName, SystType::kSpline);
83  //Keep track of this for all the samples
84  GlobalSystIndex.push_back(GlobalSystIndex_Sample);
85 
86  std::vector<SplineInterpolation> SplineInterpolation_Sample = ParHandler->GetSplineInterpolationFromSampleName(SampleName);
87  // Keep track of this for all samples
88  SplineInterpolationTypes.push_back(SplineInterpolation_Sample);
89 
90  std::vector<std::string> SplineFileParPrefixNames_Sample = ParHandler->GetSplineParsNamesFromSampleName(SampleName);
91  SplineFileParPrefixNames.push_back(SplineFileParPrefixNames_Sample);
92 
93  MACH3LOG_INFO("Create SplineModeVecs_Sample");
94  std::vector<std::vector<int>> SplineModeVecs_Sample = StripDuplicatedModes(ParHandler->GetSplineModeVecFromSampleName(SampleName));
95  MACH3LOG_INFO("SplineModeVecs_Sample is of size {}", SplineModeVecs_Sample.size());
96  SplineModeVecs.push_back(SplineModeVecs_Sample);
97 
98  MACH3LOG_INFO("SplineModeVecs is of size {}", SplineModeVecs.size());
99 
100  int nOscChan = int(OscChanFileNames.size());
101  nOscChans.push_back(nOscChan);
102 
103  PrintSampleDetails(SampleTitle);
104 
105  std::vector<std::vector<TAxis *>> SampleBinning(nOscChan);
106  for (int iOscChan = 0; iOscChan < nOscChan; iOscChan++)
107  {
108  SampleBinning[iOscChan] = FindSplineBinning(OscChanFileNames[iOscChan], SampleTitle);
109  }
110  MACH3LOG_INFO("#----------------------------------------------------------------------------------------------------------------------------------#");
111  SplineBinning.push_back(SampleBinning);
112 
113  BuildSampleIndexingArray(SampleTitle);
114  PrintArrayDetails(SampleTitle);
115  MACH3LOG_INFO("#----------------------------------------------------------------------------------------------------------------------------------#");
116 
117  FillSampleArray(SampleTitle, OscChanFileNames);
118  MACH3LOG_INFO("#----------------------------------------------------------------------------------------------------------------------------------#");
119 }
120 
121 //****************************************
123 //****************************************
124  // Map: iSample → iSyst → modeSuffix → {totalSplines, zeroCount}
125  std::map<unsigned int, std::map<unsigned int, std::map<std::string, std::pair<unsigned int, unsigned int>>>> systZeroCounts;
126  for (const auto& entry : IndexVect) {
127  unsigned int iSample = entry.iSample;
128  unsigned int iSyst = entry.iSyst;
129 
130  std::string SampleName = SampleNames[iSample];
131  // Get the mode suffix string
132  std::string modeSuffix = Modes->GetSplineSuffixFromMaCh3Mode(SplineModeVecs[iSample][entry.iSyst][entry.iMode]);
133  auto& counts = systZeroCounts[iSample][iSyst][modeSuffix];
134 
135  counts.first++; // totalSplines
136  if (entry.value == -1)
137  {
138  counts.second++; // zeroCount
139  if (counts.second > 1)
140  {
142  "Sample '{}' | OscChan {} | Syst '{}' | Mode '{}' | Var1 {} | Var2 {} | Var3 {} => Value: {}",
143  SampleTitles[iSample],
144  entry.iOscChan,
145  SplineFileParPrefixNames[iSample][iSyst],
146  modeSuffix,
147  entry.iVar1,
148  entry.iVar2,
149  entry.iVar3,
150  entry.value
151  );
152  }
153  }
154  }
155 
156  // KS: Let's print this atrocious mess...
157  for (const auto& samplePair : systZeroCounts) {
158  unsigned int iSample = samplePair.first;
159  std::vector<std::string> SplineFileParPrefixNames_Sample = ParHandler->GetParsNamesFromSampleName(SampleNames[iSample], kSpline);
160  for (const auto& systPair : samplePair.second) {
161  unsigned int iSyst = systPair.first;
162  const auto& systName = SplineFileParPrefixNames_Sample[iSyst];
163  for (const auto& modePair : systPair.second) {
164  const auto& modeSuffix = modePair.first;
165  const auto& counts = modePair.second;
167  "Sample '{}': Systematic '{}' has missing splines in mode '{}'. Expected Splines: {}, Missing Splines: {}",
168  SampleTitles[iSample],
169  systName,
170  modeSuffix,
171  counts.first,
172  counts.second
173  );
174  }
175  }
176  }
177 }
178 
179 //****************************************
181 //****************************************
182  PrepForReweight();
184 
187  MACH3LOG_ERROR("Something's gone wrong when we tried to get the size of your monolith");
188  MACH3LOG_ERROR("MonolithSize is {}", MonolithSize);
189  MACH3LOG_ERROR("MonolithIndex is {}", MonolithIndex);
190  throw MaCh3Exception(__FILE__ , __LINE__ );
191  }
192 
193  MACH3LOG_INFO("Now transferring splines to a monolith if size {}", MonolithSize);
194  // Maps single spline object with single parameter
197  isflatarray = new bool[MonolithSize];
198 
201 
202  for (const auto& entry : IndexVect) {
203  int splineindex = entry.value;
204  weightvec_Monolith[splineindex] = 1.0;
205 
206  bool foundUniqueSpline = false;
207  // We are trying to match Spline Object with single parameter (like MAQE)
208  for (int iUniqueSyst = 0; iUniqueSyst < nParams; iUniqueSyst++)
209  {
210  if (SplineFileParPrefixNames[entry.iSample][entry.iSyst] == UniqueSystNames[iUniqueSyst])
211  {
212  uniquesplinevec_Monolith[splineindex] = iUniqueSyst;
213  foundUniqueSpline = true;
214  break;
215  }
216  } //unique syst loop end
217 
218  // If current spline object hasn't been matched with actual parameter this means misconfiguration
219  if (!foundUniqueSpline)
220  {
221  MACH3LOG_ERROR("Unique spline index not found");
222  MACH3LOG_ERROR("For Spline {}", SplineFileParPrefixNames[entry.iSample][entry.iSyst]);
223  MACH3LOG_ERROR("Couldn't match {} with any of the following {} systs:", SplineFileParPrefixNames[entry.iSample][entry.iSyst], nParams);
224  for (int iUniqueSyst = 0; iUniqueSyst < nParams; iUniqueSyst++)
225  {
226  MACH3LOG_ERROR("{},", UniqueSystNames.at(iUniqueSyst));
227  }//unique syst loop end
228  throw MaCh3Exception(__FILE__ , __LINE__ );
229  }
230 
231  int splineKnots;
232  if(splinevec_Monolith[splineindex]){
233  isflatarray[splineindex] = false;
234  splineKnots=splinevec_Monolith[splineindex]->GetNp();
235 
236  //Now to fill up our coefficient arrayss
237  M3::float_t* tmpXCoeffArr = new M3::float_t[splineKnots];
238  M3::float_t* tmpManyCoeffArr = new M3::float_t[splineKnots*_nCoeff_];
239 
240  int iCoeff=coeffindexvec[splineindex];
241  getSplineCoeff_SepMany(splineindex, tmpXCoeffArr, tmpManyCoeffArr);
242 
243  for(int i = 0; i < splineKnots; i++){
244  xcoeff_arr[iCoeff+i] = tmpXCoeffArr[i];
245 
246  for(int j = 0; j < _nCoeff_; j++){
247  manycoeff_arr[(iCoeff+i)*_nCoeff_+j]=tmpManyCoeffArr[i*_nCoeff_+j];
248  }
249  }
250  delete[] tmpXCoeffArr;
251  delete[] tmpManyCoeffArr;
252  } else {
253  isflatarray[splineindex]=true;
254  }
255  }
256 }
257 
258 // *****************************************
260 // *****************************************
261  // There's a parameter mapping that goes from spline parameter to a global parameter index
262  // Find the spline segments
264 
265  //KS: Huge MP loop over all valid splines
267 }
268 
269 //****************************************
271 //****************************************
272  #ifdef MULTITHREAD
273  #pragma omp parallel for simd
274  #endif
275  for (size_t iCoeff = 0; iCoeff < uniquecoeffindices.size(); ++iCoeff)
276  {
277  const int iSpline = uniquecoeffindices[iCoeff];
278  const short int uniqueIndex = short(uniquesplinevec_Monolith[iSpline]);
279  const short int currentsegment = short(SplineSegments[uniqueIndex]);
280 
281  const int segCoeff = coeffindexvec[iSpline]+currentsegment;
282  const int coeffOffset = segCoeff * _nCoeff_;
283  // These are what we can extract from the TSpline3
284  const M3::float_t y = manycoeff_arr[coeffOffset+kCoeffY];
285  const M3::float_t b = manycoeff_arr[coeffOffset+kCoeffB];
286  const M3::float_t c = manycoeff_arr[coeffOffset+kCoeffC];
287  const M3::float_t d = manycoeff_arr[coeffOffset+kCoeffD];
288 
289  // Get the variation for this reconfigure for the ith parameter
291  const M3::float_t xvar = (*SplineInfoArray[uniqueIndex].splineParsPointer);
292  // The Delta(x) = xvar - x
293  const M3::float_t dx = xvar - xcoeff_arr[segCoeff];
294 
295  //Speedy 1% time boost https://en.cppreference.com/w/c/numeric/math/fma (see ND code!)
296  M3::float_t weight = M3::fmaf_t(dx, M3::fmaf_t(dx, M3::fmaf_t(dx, d, c), b), y);
297  //This is the speedy version of writing dx^3+b*dx^2+c*dx+d
298 
299  //ETA - do we need this? We check later for negative weights and I wonder if this is even
300  //possible with the fmaf line above?
301  if(weight < 0){weight = 0.;} //Stops is getting negative weights
302 
303  weightvec_Monolith[iSpline] = weight;
304  }
305 }
306 
307 //****************************************
308 //Creates an array to be filled with monolith indexes for each sample (allows for indexing between 7D binning and 1D Vector)
309 //Only need 1 indexing array everything else interfaces with this to get binning properties
310 void BinnedSplineHandler::BuildSampleIndexingArray(const std::string& SampleTitle) {
311 //****************************************
312  int iSample = GetSampleIndex(SampleTitle);
313  for (int iOscChan = 0; iOscChan < nOscChans[iSample]; ++iOscChan)
314  {
315  for (int iSyst = 0; iSyst < nSplineParams[iSample]; ++iSyst)
316  {
317  int nModesInSyst = static_cast<int>(SplineModeVecs[iSample][iSyst].size());
318  for (int iMode = 0; iMode < nModesInSyst; ++iMode)
319  {
320  const int nBins1 = SplineBinning[iSample][iOscChan][0]->GetNbins();
321  const int nBins2 = SplineBinning[iSample][iOscChan][1]->GetNbins();
322  const int nBins3 = SplineBinning[iSample][iOscChan][2]->GetNbins();
323  for (int iVar1 = 0; iVar1 < nBins1; ++iVar1) {
324  for (int iVar2 = 0; iVar2 < nBins2; ++iVar2) {
325  for (int iVar3 = 0; iVar3 < nBins3; ++iVar3) {
326  SplineIndex entry;
327  entry.value = -1;
328  entry.iSample = iSample;
329  entry.iOscChan = iOscChan;
330  entry.iSyst = iSyst;
331  entry.iMode = iMode;
332  entry.iVar1 = iVar1;
333  entry.iVar2 = iVar2;
334  entry.iVar3 = iVar3;
335  IndexVect.push_back(entry);
336  }
337  }
338  }
339  }
340  }
341  }
342 }
343 
344 //****************************************
345 std::vector<TAxis *> BinnedSplineHandler::FindSplineBinning(const std::string& FileName, const std::string& SampleTitle) {
346 //****************************************
347  int iSample = GetSampleIndex(SampleTitle);
348 
349  //Try declaring these outside of TFile so they aren't owned by File
350  constexpr int nDummyBins = 1;
351  constexpr double DummyEdges[2] = {-1e15, 1e15};
352  TAxis* DummyAxis = new TAxis(nDummyBins, DummyEdges);
353  TH2F* Hist2D = nullptr;
354  TH3F* Hist3D = nullptr;
355 
356  auto File = std::unique_ptr<TFile>(TFile::Open(FileName.c_str(), "READ"));
357  if (!File || File->IsZombie())
358  {
359  MACH3LOG_ERROR("File {} not found", FileName);
360  MACH3LOG_ERROR("This is caused by something here! {} : {}", __FILE__, __LINE__);
361  throw MaCh3Exception(__FILE__ , __LINE__ );
362  }
363 
364  MACH3LOG_INFO("Finding binning for:");
365  MACH3LOG_INFO("{}", FileName);
366 
367  std::string TemplateName = "dev_tmp_0_0";
368  TObject *Obj = File->Get(TemplateName.c_str());
369  //If you can't find dev_tmp_0_0 then this will cause a problem
370  if (!Obj)
371  {
372  TemplateName = "dev_tmp.0.0";
373  Obj = File->Get(TemplateName.c_str());
374  if (!Obj)
375  {
376  MACH3LOG_ERROR("Could not find dev_tmp_0_0 in spline file. Spline binning cannot be set!");
377  MACH3LOG_ERROR("FileName: {}", FileName);
378  throw MaCh3Exception(__FILE__ , __LINE__ );
379  }
380  }
381 
382  //Now check if dev_tmp_0_0 is a TH2 i.e. specifying the dimensions of the splines is 2D
383  bool isHist2D = Obj->IsA() == TH2F::Class();
384  //For T2K annoyingly all objects are TH3Fs
385  bool isHist3D = Obj->IsA() == TH3F::Class();
386  if (!isHist2D && !isHist3D)
387  {
388  MACH3LOG_ERROR("Object doesn't inherit from either TH2D and TH3D - Odd A");
389  throw MaCh3Exception(__FILE__ , __LINE__ );
390  }
391 
392  if (isHist2D)
393  {
394  if (Dimensions[iSample] != 2)
395  {
396  MACH3LOG_ERROR("Trying to load a 2D spline template when nDim={}", Dimensions[iSample]);
397  throw MaCh3Exception(__FILE__, __LINE__);
398  }
399  Hist2D = File->Get<TH2F>(TemplateName.c_str());
400  }
401 
402  if (isHist3D)
403  {
404  Hist3D = File->Get<TH3F>((TemplateName.c_str()));
405 
406  if (Dimensions[iSample] != 3 && Hist3D->GetZaxis()->GetNbins() != 1)
407  {
408  MACH3LOG_ERROR("Trying to load a 3D spline template when nDim={}", Dimensions[iSample]);
409  throw MaCh3Exception(__FILE__ , __LINE__ );
410  }
411  Hist3D = File->Get<TH3F>(TemplateName.c_str());
412  }
413 
414  std::vector<TAxis*> ReturnVec;
415  // KS: Resize to reduce impact of push back and memory fragmentation
416  ReturnVec.resize(3);
417  if (Dimensions[iSample] == 2) {
418  if (isHist2D) {
419  ReturnVec[0] = static_cast<TAxis*>(Hist2D->GetXaxis()->Clone());
420  ReturnVec[1] = static_cast<TAxis*>(Hist2D->GetYaxis()->Clone());
421  ReturnVec[2] = static_cast<TAxis*>(DummyAxis->Clone());
422  } else if (isHist3D) {
423  ReturnVec[0] = static_cast<TAxis*>(Hist3D->GetXaxis()->Clone());
424  ReturnVec[1] = static_cast<TAxis*>(Hist3D->GetYaxis()->Clone());
425  ReturnVec[2] = static_cast<TAxis*>(DummyAxis->Clone());
426  }
427  } else if (Dimensions[iSample] == 3) {
428  ReturnVec[0] = static_cast<TAxis*>(Hist3D->GetXaxis()->Clone());
429  ReturnVec[1] = static_cast<TAxis*>(Hist3D->GetYaxis()->Clone());
430  ReturnVec[2] = static_cast<TAxis*>(Hist3D->GetZaxis()->Clone());
431  } else {
432  MACH3LOG_ERROR("Number of dimensions not valid! Given: {}", Dimensions[iSample]);
433  throw MaCh3Exception(__FILE__, __LINE__);
434  }
435 
436  for (unsigned int iAxis = 0; iAxis < ReturnVec.size(); ++iAxis) {
437  PrintBinning(ReturnVec[iAxis]);
438  }
439 
440  MACH3LOG_INFO("Left PrintBinning now tidying up");
441  delete DummyAxis;
442 
443  return ReturnVec;
444 }
445 
446 //****************************************
447 int GetSplineIndex(const std::vector<SplineIndex>& vec,
448  const int sample, const int oscchan, const int syst, const int mode,
449  const int var1bin, const int var2bin, const int var3bin) {
450 //****************************************
452  for (size_t i = 0; i < vec.size(); i++)
453  {
454  const auto& entry = vec[i];
455  if (entry.iSample == sample &&
456  entry.iOscChan == oscchan &&
457  entry.iSyst == syst &&
458  entry.iMode == mode &&
459  entry.iVar1 == var1bin &&
460  entry.iVar2 == var2bin &&
461  entry.iVar3 == var3bin)
462  {
463  return static_cast<int>(i);
464  }
465  }
466 
467  MACH3LOG_ERROR("Index not found! sample={} oscchan={} syst={} mode={} var1={} var2={} var3={}",
468  sample, oscchan, syst, mode, var1bin, var2bin, var3bin);
469  throw MaCh3Exception(__FILE__, __LINE__);
470 }
471 
472 //****************************************
473 const M3::float_t* BinnedSplineHandler::RetPointer(const int sample, const int oscchan, const int syst, const int mode,
474  const int var1bin, const int var2bin, const int var3bin) const {
475 //****************************************
476  auto Index = GetSplineIndex(IndexVect, sample, oscchan, syst, mode, var1bin, var2bin, var3bin);
477  return &weightvec_Monolith[IndexVect[Index].value];
478 }
479 
480 //****************************************
481 int BinnedSplineHandler::CountNumberOfLoadedSplines(bool NonFlat, int Verbosity) {
482 //****************************************
483  std::vector<int> SampleAll(SampleTitles.size(), 0);
484  std::vector<int> SampleNonFlat(SampleTitles.size(), 0);
485 
486  int FullCounter_All = 0;
487  int FullCounter_NonFlat = 0;
488 
489  for (unsigned int index = 0; index < IndexVect.size(); index++)
490  {
491  const auto& entry = IndexVect[index];
492 
493  int iSample = entry.iSample;
494 
495  std::string SampleTitle = SampleTitles[iSample];
496 
497 
498  if (!isValidSplineIndex(SampleTitle, entry.iOscChan, entry.iSyst,
499  entry.iMode, entry.iVar1,
500  entry.iVar2, entry.iVar3)) {
501  continue;
502  }
503  SampleAll[iSample]++;
504 
505  if (splinevec_Monolith[entry.value]) {
506  SampleNonFlat[iSample]++;
507  }
508  }
509 
510  // Print per-sample summary
511  for (size_t iSample = 0; iSample < SampleTitles.size(); iSample++)
512  {
513  MACH3LOG_DEBUG("{:<10} has {:<10} splines, of which {:<10} are not flat",
514  SampleTitles[iSample],
515  SampleAll[iSample],
516  SampleNonFlat[iSample]);
517 
518  FullCounter_All += SampleAll[iSample];
519  FullCounter_NonFlat += SampleNonFlat[iSample];
520  }
521 
522  if (Verbosity > 0) {
523  MACH3LOG_INFO("Total number of splines loaded: {}", FullCounter_All);
524  MACH3LOG_INFO("Total number of non-flat splines loaded: {}", FullCounter_NonFlat);
525  }
526 
527  if (NonFlat) {
528  return FullCounter_NonFlat;
529  } else {
530  return FullCounter_All;
531  }
532 }
533 
534 //****************************************
536 //****************************************
537  std::vector<TSpline3_red*> UniqueSystSplines;
538  bool FoundNonFlatSpline = false;
539  int SampleCounter = M3::_BAD_INT_;
540  int SystCounter = M3::_BAD_INT_;
541  // DB Find all the Unique systs across each sample and oscillation channel
542  // This assumes that each occurrence of the same systematic spline has the same knot spacing
543  // Which is a reasonable assumption for the current implementation of spline evaluations
544  for (const auto& entry : IndexVect)
545  {
546  int splineindex = entry.value;
547  // KS: reset if we moved to another sample or syst
548  if(SampleCounter != entry.iSample || SystCounter != entry.iSyst) {
549  SampleCounter = entry.iSample;
550  SystCounter = entry.iSyst;
551  FoundNonFlatSpline = false;
552  }
553  std::string SystName = SplineFileParPrefixNames[entry.iSample][entry.iSyst];
554  bool FoundSyst = false;
555  for (unsigned int iFoundSyst = 0; iFoundSyst < UniqueSystNames.size(); iFoundSyst++) {
556  if (SystName == UniqueSystNames[iFoundSyst]) {
557  FoundSyst = true;
558  }
559  }
560  if (FoundSyst) continue;
561 
562  if (splinevec_Monolith[splineindex])
563  {
564  UniqueSystSplines.push_back(splinevec_Monolith[splineindex]);
565  UniqueSystIndices.push_back(GlobalSystIndex[entry.iSample][entry.iSyst]);
566 
567  FoundNonFlatSpline = true;
568  }
569  if (FoundNonFlatSpline) {
570  UniqueSystNames.push_back(SystName);
571  } else {
572  MACH3LOG_INFO("{} syst has no response in sample {}", SystName, entry.iSample);
573  MACH3LOG_INFO("Whilst this isn't necessarily a problem, it seems odd");
574  }
575  } // end loop over indices
576  nParams = static_cast<short int>(UniqueSystSplines.size());
577 
578  // DB Find the number of splines knots which assumes each instance of the syst has the same number of knots
579  SplineSegments = new short int[nParams]();
580  ParamValues = new float[nParams]();
581  SplineInfoArray.resize(nParams);
582  for (int iSpline = 0; iSpline < nParams; iSpline++)
583  {
584  SplineInfoArray[iSpline].nPts = static_cast<M3::int_t>(UniqueSystSplines[iSpline]->GetNp());
585  SplineInfoArray[iSpline].xPts.resize(SplineInfoArray[iSpline].nPts);
586  SplineInfoArray[iSpline].splineParsPointer = ParHandler->RetPointer(UniqueSystIndices[iSpline]);
587  for (int iKnot = 0; iKnot < SplineInfoArray[iSpline].nPts; iKnot++)
588  {
589  M3::float_t xPoint;
590  M3::float_t yPoint;
591  UniqueSystSplines[iSpline]->GetKnot(iKnot, xPoint, yPoint);
592  SplineInfoArray[iSpline].xPts[iKnot] = xPoint;
593  }
594  //ETA - let this just be set as the first segment by default
595  SplineSegments[iSpline] = 0;
596  ParamValues[iSpline] = 0.;
597  }
598 
599  MACH3LOG_INFO("nUniqueSysts: {}", nParams);
600  MACH3LOG_INFO("{:<15} | {:<20} | {:<6}", "Spline Index", "Syst Name", "nKnots");
601  for (int iUniqueSyst = 0; iUniqueSyst < nParams; iUniqueSyst++)
602  {
603  MACH3LOG_INFO("{:<15} | {:<20} | {:<6}", iUniqueSyst, UniqueSystNames[iUniqueSyst], SplineInfoArray[iUniqueSyst].nPts);
604  }
605 
606  int nCombinations_FlatSplines = 0;
607  int nCombinations_All = 0;
608  // DB Now actually loop over splines to determine which are all null i.e. flat
609  for (unsigned int index = 0; index < IndexVect.size(); index++)
610  {
611  int splineindex = IndexVect[index].value;;
612  nCombinations_All++;
613  if (!splinevec_Monolith[splineindex]) {
614  nCombinations_FlatSplines++;
615  }
616  }
617 
618  // We need to grab the maximum number of knots
619  MACH3LOG_INFO("Number of combinations of Sample, OscChan, Syst and Mode which have entirely flat response: {} / {}", nCombinations_FlatSplines, nCombinations_All);
620 }
621 
622 //****************************************
623 // Rather work with spline coefficients in the splines, let's copy ND and use coefficient arrays
624 void BinnedSplineHandler::getSplineCoeff_SepMany(int splineindex, M3::float_t* &xArray, M3::float_t* &manyArray) {
625 //****************************************
626  //No point evaluating a flat spline
627  int nPoints = splinevec_Monolith[splineindex]->GetNp();
628 
629  for (int i = 0; i < nPoints; i++) {
630  xArray[i] = 1.0;
631  for (int j = 0; j < _nCoeff_; j++) {
632  manyArray[i*_nCoeff_+j] = 1.0;
633  }
634  }
635 
636  for(int i=0; i<nPoints; i++) {
637  M3::float_t x = M3::float_t(-999.99);
638  M3::float_t y = M3::float_t(-999.99);
639  M3::float_t b = M3::float_t(-999.99);
640  M3::float_t c = M3::float_t(-999.99);
641  M3::float_t d = M3::float_t(-999.99);
642  splinevec_Monolith[splineindex]->GetCoeff(i, x, y, b, c, d);
643 
644  // Store the coefficients for each knot contiguously in memory
645  // 4 because manyArray stores y,b,c,d
646  xArray[i] = x;
647  manyArray[i * _nCoeff_ + kCoeffY] = y;
648  manyArray[i * _nCoeff_ + kCoeffB] = b;
649  manyArray[i * _nCoeff_ + kCoeffC] = c;
650  manyArray[i * _nCoeff_ + kCoeffD] = d;
651  }
652 
653  //We now clean up the splines!
654  delete splinevec_Monolith[splineindex];
655  splinevec_Monolith[splineindex] = nullptr;
656 }
657 
658 
659 //****************************************
660 //Returns sample index in
661 int BinnedSplineHandler::GetSampleIndex(const std::string& SampleTitle) const{
662 //****************************************
663  for (size_t iSample = 0; iSample < SampleTitles.size(); ++iSample) {
664  if (SampleTitle == SampleTitles[iSample]) {
665  return static_cast<int>(iSample);
666  }
667  }
668  MACH3LOG_ERROR("Sample name not found: {}", SampleTitle);
669  throw MaCh3Exception(__FILE__, __LINE__);
670 }
671 
672 //****************************************
673 void BinnedSplineHandler::PrintSampleDetails(const std::string& SampleTitle) const {
674 //****************************************
675  const int iSample = GetSampleIndex(SampleTitle);
676 
677  MACH3LOG_INFO("Details about sample: {:<20}", SampleTitles[iSample]);
678  MACH3LOG_INFO("\t Dimension: {:<35}", Dimensions[iSample]);
679  MACH3LOG_INFO("\t nSplineParam: {:<35}", nSplineParams[iSample]);
680  MACH3LOG_INFO("\t nOscChan: {:<35}", nOscChans[iSample]);
681 }
682 
683 //****************************************
684 void BinnedSplineHandler::PrintArrayDetails(const std::string& SampleTitle) const {
685 //****************************************
686  int iSample = GetSampleIndex(SampleTitle);
687  // count oscillation channels
688  std::map<int, std::set<int>> OscToSysts;
689 
690  for (const auto& entry : IndexVect) {
691  if (entry.iSample != iSample) continue;
692  OscToSysts[entry.iOscChan].insert(entry.iSyst);
693  }
694  MACH3LOG_INFO("Sample {} has {} oscillation channels", SampleTitle, OscToSysts.size());
695 
696  for (const auto& OscPair : OscToSysts) {
697  int osc = OscPair.first;
698  const std::set<int>& SystSet = OscPair.second;
699  MACH3LOG_INFO("Oscillation channel {} has {} systematics", osc, SystSet.size());
700  }
701 }
702 
703 //****************************************
704 bool BinnedSplineHandler::isValidSplineIndex(const std::string& SampleTitle, int iOscChan,
705  int iSyst, int iMode, int iVar1, int iVar2, int iVar3) const {
706 //****************************************
707  int iSample = GetSampleIndex(SampleTitle);
708 
709  // find matching entry in flat structure
710  bool found = false;
711 
712  for (const auto& entry : IndexVect)
713  {
714  if (entry.iSample == iSample &&
715  entry.iOscChan == iOscChan &&
716  entry.iSyst == iSyst &&
717  entry.iMode == iMode &&
718  entry.iVar1 == iVar1 &&
719  entry.iVar2 == iVar2 &&
720  entry.iVar3 == iVar3)
721  {
722  found = true;
723  break;
724  }
725  }
726 
727  if (!found)
728  {
729  MACH3LOG_ERROR("Given iSample: {}", iSample);
730  MACH3LOG_ERROR("Given iOscChan: {}", iOscChan);
731  MACH3LOG_ERROR("Given iSyst: {}", iSyst);
732  MACH3LOG_ERROR("Given iMode: {}", iMode);
733  MACH3LOG_ERROR("Given iVar1: {}", iVar1);
734  MACH3LOG_ERROR("Given iVar2: {}", iVar2);
735  MACH3LOG_ERROR("Given iVar3: {}", iVar3);
736  MACH3LOG_ERROR("Come visit me at : {} : {}", __FILE__, __LINE__);
737  throw MaCh3Exception(__FILE__, __LINE__);
738  }
739 
740  return true;
741 }
742 
743 //****************************************
744 void BinnedSplineHandler::PrintBinning(TAxis *Axis) const {
745 //****************************************
746  const int NBins = Axis->GetNbins();
747  std::string text = "";
748  for (int iBin = 0; iBin <= NBins; iBin++) {
749  text += fmt::format("{} ", Axis->GetXbins()->GetAt(iBin));
750  }
751  MACH3LOG_INFO("{}", text);
752 }
753 
754 //****************************************
755 std::vector< std::vector<int> > BinnedSplineHandler::GetEventSplines(const std::string& SampleTitle,
756  int iOscChan, int EventMode, double Var1Val,
757  double Var2Val, double Var3Val) {
758 //****************************************
759  std::vector<std::vector<int>> ReturnVec;
760  int SampleIndex = GetSampleIndex(SampleTitle);
761 
762  int Mode = -1;
763  std::string SuffixForEventMode = Modes->GetSplineSuffixFromMaCh3Mode(EventMode);
764  for (int iMode = 0; iMode< Modes->GetNModes(); iMode++) {
765  if (SuffixForEventMode == Modes->GetSplineSuffixFromMaCh3Mode(iMode)) {
766  Mode = iMode;
767  break;
768  }
769  }
770  if (Mode == -1) {
771  return ReturnVec;
772  }
773 
774  std::vector<int> bins;
775  std::vector<double> vars = {Var1Val, Var2Val, Var3Val};
776  for (size_t i = 0; i < vars.size(); ++i) {
777  int bin = SplineBinning[SampleIndex][iOscChan][i]->FindBin(vars[i]) - 1;
778  if (bin < 0 || bin >= SplineBinning[SampleIndex][iOscChan][i]->GetNbins()) {
779  return ReturnVec;
780  }
781  bins.push_back(bin);
782  }
783  int Var1Bin = bins[0]; int Var2Bin = bins[1]; int Var3Bin = bins[2];
784 
785  for(int iSyst=0; iSyst < nSplineParams[SampleIndex]; iSyst++){
786  std::vector<int> spline_modes = SplineModeVecs[SampleIndex][iSyst];
787  int nSampleModes = static_cast<int>(spline_modes.size());
788 
789  //ETA - look here at the length of spline_modes and what you're actually comparing against
790  for(int iMode = 0; iMode<nSampleModes; iMode++) {
791  //Only consider if the event mode (Mode) matches ones of the spline modes
792  if (Mode == spline_modes[iMode]) {
793  int index = GetSplineIndex(IndexVect, SampleIndex, iOscChan, iSyst, iMode, Var1Bin, Var2Bin, Var3Bin);
794  int splineID = IndexVect[index].value;
795  //Also check that the spline isn't flat
796  if(!isflatarray[splineID]) {
797  ReturnVec.push_back({SampleIndex, iOscChan, iSyst, iMode, Var1Bin, Var2Bin, Var3Bin});
798  }
799  }
800  }
801  }
802  return ReturnVec;
803 }
804 
805 //****************************************
806 // checks if there are multiple modes with the same SplineSuffix
807 // (for example if CCRES and CCCoherent are treated as one spline mode)
808 std::vector< std::vector<int> > BinnedSplineHandler::StripDuplicatedModes(const std::vector< std::vector<int> >& InputVector) const {
809 //****************************************
810  //ETA - this is of size nPars from the syst model
811  size_t InputVectorSize = InputVector.size();
812  std::vector< std::vector<int> > ReturnVec(InputVectorSize);
813 
814  //ETA - loop over all systematics
815  for (size_t iSyst=0;iSyst<InputVectorSize;iSyst++) {
816  std::vector<int> TmpVec;
817  std::vector<std::string> TestVec;
818 
819  //Loop over the modes that we've listed in ParHandler
820  for (unsigned int iMode = 0 ; iMode < InputVector[iSyst].size() ; iMode++) {
821  int Mode = InputVector[iSyst][iMode];
822  std::string ModeName = Modes->GetSplineSuffixFromMaCh3Mode(Mode);
823 
824  bool IncludeMode = true;
825  for (auto TestString : TestVec) {
826  if (ModeName == TestString) {
827  IncludeMode = false;
828  break;
829  }
830  }
831 
832  if (IncludeMode) {
833  TmpVec.push_back(Mode);
834  TestVec.push_back(ModeName);
835  }
836  }
837 
838  ReturnVec[iSyst] = TmpVec;
839  }
840  return ReturnVec;
841 }
842 
843 void BinnedSplineHandler::FillSampleArray(const std::string& SampleTitle, const std::vector<std::string>& OscChanFileNames)
844 {
845  int iSample = GetSampleIndex(SampleTitle);
846  int nOscChannels = nOscChans[iSample];
847 
848  for (int iOscChan = 0; iOscChan < nOscChannels; iOscChan++) {
849  MACH3LOG_INFO("Processing: {}", OscChanFileNames[iOscChan]);
850  TSpline3* mySpline = nullptr;
851  TSpline3_red* Spline = nullptr;
852  TString Syst, Mode;
853  int nKnots, SystNum, ModeNum, Var1Bin, Var2Bin, Var3Bin = M3::_BAD_INT_;
854  double x,y = M3::_BAD_DOUBLE_;
855  bool isFlat = true;
856 
857  std::set<std::string> SplineFileNames;
858 
859  auto File = std::unique_ptr<TFile>(TFile::Open(OscChanFileNames[iOscChan].c_str()));
860 
861  if (!File || File->IsZombie()) {
862  MACH3LOG_ERROR("File {} not found", OscChanFileNames[iOscChan]);
863  throw MaCh3Exception(__FILE__, __LINE__);
864  }
865 
866  //This is the MC specific part of the code
867  //i.e. we always assume that the splines are just store in single TDirectory and they're all in there as single objects
868  for (auto k : *File->GetListOfKeys()) {
869  auto Key = static_cast<TKey*>(k);
870  TClass *Class = gROOT->GetClass(Key->GetClassName(), false);
871  if(!Class->InheritsFrom("TSpline3")) {
872  continue;
873  }
874 
875  std::string FullSplineName = std::string(Key->GetName());
876 
877  if (SplineFileNames.count(FullSplineName) > 0) {
878  MACH3LOG_CRITICAL("Skipping spline - Found a spline whose name has already been encountered before: {}", FullSplineName);
879  continue;
880  }
881  SplineFileNames.insert(FullSplineName);
882 
883  std::vector<std::string> Tokens = GetTokensFromSplineName(FullSplineName);
884 
885  if (Tokens.size() != kNTokens) {
886  MACH3LOG_ERROR("Invalid tokens from spline name - Expected {} tokens. Check implementation in GetTokensFromSplineName()", static_cast<int>(kNTokens));
887  throw MaCh3Exception(__FILE__, __LINE__);
888  }
889 
890  Syst = Tokens[kSystToken];
891  Mode = Tokens[kModeToken];
892  Var1Bin = std::stoi(Tokens[kVar1BinToken]);
893  Var2Bin = std::stoi(Tokens[kVar2BinToken]);
894  Var3Bin = std::stoi(Tokens[kVar3BinToken]);
895 
896  SystNum = -1;
897  for (unsigned iSyst = 0; iSyst < SplineFileParPrefixNames[iSample].size(); iSyst++) {
898  if (Syst == SplineFileParPrefixNames[iSample][iSyst]) {
899  SystNum = iSyst;
900  break;
901  }
902  }
903 
904  // If the syst doesn't match any of the spline names then skip it
905  if (SystNum == -1){
906  MACH3LOG_DEBUG("Couldn't match!!");
907  MACH3LOG_DEBUG("Couldn't Match any systematic name in ParameterHandler with spline name: {}" , FullSplineName);
908  continue;
909  }
910 
911  ModeNum = -1;
912  for (unsigned int iMode = 0; iMode < SplineModeVecs[iSample][SystNum].size(); iMode++) {
913  if (Mode == Modes->GetSplineSuffixFromMaCh3Mode(SplineModeVecs[iSample][SystNum][iMode])) {
914  ModeNum = iMode;
915  break;
916  }
917  }
918 
919  if (ModeNum == -1) {
920  //DB - If you have splines in the root file that you don't want to use (e.g. removing a mode from a syst), this will cause a throw
921  // Therefore include as debug warning and continue instead
922  MACH3LOG_DEBUG("Couldn't find mode for {} in {}. Problem Spline is : {} ", Mode, Syst, FullSplineName);
923  continue;
924  }
925 
926  mySpline = Key->ReadObject<TSpline3>();
927 
928  if (isValidSplineIndex(SampleTitle, iOscChan, SystNum, ModeNum, Var1Bin, Var2Bin, Var3Bin)) { // loop over all the spline knots and check their value
929  MACH3LOG_TRACE("Pushed back monolith for spline {}", FullSplineName);
930  // if the value is 1 then set the flat bool to false
931  nKnots = mySpline->GetNp();
932  isFlat = true;
933  for (int iKnot = 0; iKnot < nKnots; iKnot++) {
934  mySpline->GetKnot(iKnot, x, y);
935  if (y < 0.99999 || y > 1.00001)
936  {
937  isFlat = false;
938  break;
939  }
940  }
941 
942  //Rather than keeping a mega vector of splines then converting, this should just keep everything nice in memory!
943  int index = GetSplineIndex(IndexVect, iSample, iOscChan, SystNum, ModeNum, Var1Bin, Var2Bin, Var3Bin);
944  IndexVect[index].value = MonolithIndex;
945  coeffindexvec.push_back(CoeffIndex);
946  // Should save memory rather saving [x_i_0 ,... x_i_maxknots] for every spline!
947  if (isFlat) {
948  splinevec_Monolith.push_back(nullptr);
949  delete mySpline;
950  } else {
951  ApplyKnotWeightCapTSpline3(mySpline, SystNum, ParHandler);
952  Spline = new TSpline3_red(mySpline, SplineInterpolationTypes[iSample][SystNum]);
953  if(mySpline) delete mySpline;
954 
955  splinevec_Monolith.push_back(Spline);
956  uniquecoeffindices.push_back(MonolithIndex); //So we can get the unique coefficients and skip flat splines later on!
957  CoeffIndex+=nKnots;
958  }
959  //Incrementing MonolithIndex to keep track of number of valid spline indices
960  MonolithIndex+=1;
961  } else {
962  //Potentially you are not a valid spline index
963  delete mySpline;
964  }
965  }//End of loop over all TKeys in file
966 
967  //A bit of clean up
968  File->Delete("*");
969  File->Close();
970  } //End of oscillation channel loop
971 }
972 
973 // *****************************************
974 // Load SplineMonolith from ROOT file
975 void BinnedSplineHandler::LoadSplineFile(std::string FileName) {
976 // *****************************************
977  M3::AddPath(FileName);
978 
979  // Check for spaces in the filename
980  size_t pos = FileName.find(' ');
981  if (pos != std::string::npos) {
982  MACH3LOG_WARN("Filename ({}) contains spaces. Replacing spaces with underscores.", FileName);
983  while ((pos = FileName.find(' ')) != std::string::npos) {
984  FileName[pos] = '_';
985  }
986  }
987  auto SplineFile = std::make_unique<TFile>(FileName.c_str(), "OPEN");
988 
989  TMacro *ConfigCov = SplineFile->Get<TMacro>("ParameterHandler");
990  // Config which was in MCMC from which we are starting
991  YAML::Node CovSettings = TMacroToYAML(*ConfigCov);
992  // Config from currently used cov object
993  YAML::Node ConfigCurrent = ParHandler->GetConfig();
994 
995  if (!compareYAMLNodes(CovSettings, ConfigCurrent))
996  {
997  MACH3LOG_ERROR("Loading precomputed spline file, however encountered different YAML config, please regenerate input");
998  throw MaCh3Exception(__FILE__ , __LINE__ );
999  }
1000 
1001  LoadSettingsDir(SplineFile);
1002  LoadMonolithDir(SplineFile);
1003  LoadIndexDir(SplineFile);
1004  LoadFastSplineInfoDir(SplineFile);
1005 
1006  for (int iSpline = 0; iSpline < nParams; iSpline++) {
1007  SplineInfoArray[iSpline].splineParsPointer = ParHandler->RetPointer(UniqueSystIndices[iSpline]);
1008  }
1009  SplineFile->Close();
1010 }
1011 
1012 // *****************************************
1013 // KS: Prepare Fast Spline Info within SplineFile
1014 void BinnedSplineHandler::LoadSettingsDir(std::unique_ptr<TFile>& SplineFile) {
1015 // *****************************************
1016  TTree *Settings = SplineFile->Get<TTree>("Settings");
1017  int CoeffIndex_temp, MonolithSize_temp;
1018  short int nParams_temp;
1019  Settings->SetBranchAddress("CoeffIndex", &CoeffIndex_temp);
1020  Settings->SetBranchAddress("MonolithSize", &MonolithSize_temp);
1021  Settings->SetBranchAddress("nParams", &nParams_temp);
1022 
1023  int SplineBinning_size1, SplineBinning_size2, SplineBinning_size3;
1024  Settings->SetBranchAddress("SplineBinning_size1", &SplineBinning_size1);
1025  Settings->SetBranchAddress("SplineBinning_size2", &SplineBinning_size2);
1026  Settings->SetBranchAddress("SplineBinning_size3", &SplineBinning_size3);
1027  int SplineModeVecs_size1, SplineModeVecs_size2, SplineModeVecs_size3;
1028  Settings->SetBranchAddress("SplineModeVecs_size1", &SplineModeVecs_size1);
1029  Settings->SetBranchAddress("SplineModeVecs_size2", &SplineModeVecs_size2);
1030  Settings->SetBranchAddress("SplineModeVecs_size3", &SplineModeVecs_size3);
1031  std::vector<std::string>* SampleNames_temp = nullptr;
1032  Settings->SetBranchAddress("SampleNames", &SampleNames_temp);
1033  std::vector<std::string>* SampleTitles_temp = nullptr;
1034  Settings->SetBranchAddress("SampleTitles", &SampleTitles_temp);
1035  std::vector<int>* nSplineParams_temp = nullptr;
1036  Settings->SetBranchAddress("nSplineParams", &nSplineParams_temp);
1037  Settings->GetEntry(0);
1038 
1039  CoeffIndex = CoeffIndex_temp;
1040  MonolithSize = MonolithSize_temp;
1041  SampleNames = *SampleNames_temp;
1042  SampleTitles = *SampleTitles_temp;
1043  nSplineParams = *nSplineParams_temp;
1044 
1045  nParams = nParams_temp;
1046 
1047  SplineSegments = new short int[nParams]();
1048  ParamValues = new float[nParams]();
1049 
1050  auto Resize3D = [](auto& vec, int d1, int d2, int d3) {
1051  vec.resize(d1);
1052  for (int i = 0; i < d1; ++i) {
1053  vec[i].resize(d2);
1054  for (int j = 0; j < d2; ++j) {
1055  vec[i][j].resize(d3);
1056  }
1057  }
1058  };
1059 
1060  Resize3D(SplineBinning, SplineBinning_size1, SplineBinning_size2, SplineBinning_size3);
1061  Resize3D(SplineModeVecs, SplineModeVecs_size1, SplineModeVecs_size2, SplineModeVecs_size3);
1062 }
1063 
1064 // *****************************************
1065 // KS: Prepare Fast Spline Info within SplineFile
1066 void BinnedSplineHandler::LoadMonolithDir(std::unique_ptr<TFile>& SplineFile) {
1067 // *****************************************
1068  TTree *MonolithTree = SplineFile->Get<TTree>("MonolithTree");
1069 
1071  MonolithTree->SetBranchAddress("manycoeff", manycoeff_arr);
1072  isflatarray = new bool[MonolithSize];
1074  MonolithTree->SetBranchAddress("isflatarray", isflatarray);
1075 
1076  // Load vectors
1077  std::vector<int>* coeffindexvec_temp = nullptr;
1078  MonolithTree->SetBranchAddress("coeffindexvec", &coeffindexvec_temp);
1079  std::vector<int>* uniquecoeffindices_temp = nullptr;
1080  MonolithTree->SetBranchAddress("uniquecoeffindices", &uniquecoeffindices_temp);
1081  std::vector<int>* uniquesplinevec_Monolith_temp = nullptr;
1082  MonolithTree->SetBranchAddress("uniquesplinevec_Monolith", &uniquesplinevec_Monolith_temp);
1083  std::vector<int>* UniqueSystIndices_temp = nullptr;
1084  MonolithTree->SetBranchAddress("UniqueSystIndices", &UniqueSystIndices_temp);
1085 
1086  // Allocate and load xcoeff_arr
1088  MonolithTree->SetBranchAddress("xcoeff", xcoeff_arr);
1089 
1090  MonolithTree->GetEntry(0);
1091 
1092  coeffindexvec = *coeffindexvec_temp;
1093  uniquecoeffindices = *uniquecoeffindices_temp;
1094  uniquesplinevec_Monolith = *uniquesplinevec_Monolith_temp;
1095  UniqueSystIndices = *UniqueSystIndices_temp;
1096 }
1097 
1098 // *****************************************
1099 // KS: Prepare Fast Spline Info within SplineFile
1100 void BinnedSplineHandler::LoadIndexDir(std::unique_ptr<TFile>& SplineFile) {
1101 // *****************************************
1102  TTree *IndexTree = SplineFile->Get<TTree>("IndexVec");
1103 
1104  SplineIndex* IndexTemp = nullptr;
1105  IndexTree->SetBranchAddress("SplineIndex", &IndexTemp);
1106  IndexVect.resize(IndexTree->GetEntries());
1107  // Fill indexvec with data from IndexTree
1108  for (Long64_t iEntry = 0; iEntry < IndexTree->GetEntries(); ++iEntry) {
1109  IndexTree->GetEntry(iEntry);
1110  IndexVect[iEntry] = *IndexTemp;
1111  }
1112 
1113  // Load SplineBinning data
1114  TTree *SplineBinningTree = SplineFile->Get<TTree>("SplineBinningTree");
1115  std::vector<int> indices(3);
1116  SplineBinningTree->SetBranchAddress("i", &indices[0]);
1117  SplineBinningTree->SetBranchAddress("j", &indices[1]);
1118  SplineBinningTree->SetBranchAddress("k", &indices[2]);
1119  TAxis* axis = nullptr;
1120  SplineBinningTree->SetBranchAddress("axis", &axis);
1121 
1122  // Reconstruct TAxis objects
1123  for (Long64_t entry = 0; entry < SplineBinningTree->GetEntries(); ++entry) {
1124  SplineBinningTree->GetEntry(entry);
1125  int i = indices[0];
1126  int j = indices[1];
1127  int k = indices[2];
1128  SplineBinning[i][j][k] = static_cast<TAxis*>(axis->Clone());
1129  }
1130 
1131  std::vector<int> indices_mode(3);
1132  int mode_value;
1133  TTree *SplineModeTree = SplineFile->Get<TTree>("SplineModeTree");
1134  SplineModeTree->SetBranchAddress("i", &indices_mode[0]);
1135  SplineModeTree->SetBranchAddress("j", &indices_mode[1]);
1136  SplineModeTree->SetBranchAddress("k", &indices_mode[2]);
1137  SplineModeTree->SetBranchAddress("value", &mode_value);
1138 
1139  // Fill SplineModeVecs with values from the tree
1140  for (Long64_t entry = 0; entry < SplineModeTree->GetEntries(); ++entry) {
1141  SplineModeTree->GetEntry(entry);
1142  int i = indices_mode[0];
1143  int j = indices_mode[1];
1144  int k = indices_mode[2];
1145  SplineModeVecs[i][j][k] = mode_value;
1146  }
1147 }
1148 
1149 // *****************************************
1150 // Save SplineMonolith into ROOT file
1151 void BinnedSplineHandler::PrepareSplineFile(std::string FileName) {
1152 // *****************************************
1153  M3::AddPath(FileName);
1154  // Check for spaces in the filename
1155  size_t pos = FileName.find(' ');
1156  if (pos != std::string::npos) {
1157  MACH3LOG_WARN("Filename ({}) contains spaces. Replacing spaces with underscores.", FileName);
1158  while ((pos = FileName.find(' ')) != std::string::npos) {
1159  FileName[pos] = '_';
1160  }
1161  }
1162  // Save ROOT File
1163  auto SplineFile = std::make_unique<TFile>(FileName.c_str(), "recreate");
1164  YAML::Node ConfigCurrent = ParHandler->GetConfig();
1165  TMacro ConfigSave = YAMLtoTMacro(ConfigCurrent, "ParameterHandler");
1166  ConfigSave.Write();
1167 
1168  PrepareSettingsDir(SplineFile);
1169  PrepareMonolithDir(SplineFile);
1170  PrepareIndexDir(SplineFile);
1171  PrepareOtherInfoDir(SplineFile);
1172  PrepareFastSplineInfoDir(SplineFile);
1173 
1174  SplineFile->Close();
1175 }
1176 
1177 // *****************************************
1178 void BinnedSplineHandler::PrepareSettingsDir(std::unique_ptr<TFile>& SplineFile) const {
1179 // *****************************************
1180  TTree *Settings = new TTree("Settings", "Settings");
1181  int CoeffIndex_temp = CoeffIndex;
1182  int MonolithSize_temp = MonolithSize;
1183  short int nParams_temp = nParams;
1184 
1185  Settings->Branch("CoeffIndex", &CoeffIndex_temp, "CoeffIndex/I");
1186  Settings->Branch("MonolithSize", &MonolithSize_temp, "MonolithSize/I");
1187  Settings->Branch("nParams", &nParams_temp, "nParams/S");
1188 
1189  int SplineBinning_size1 = static_cast<int>(SplineBinning.size());
1190  int SplineBinning_size2 = (SplineBinning_size1 > 0) ? static_cast<int>(SplineBinning[0].size()) : 0;
1191  int SplineBinning_size3 = (SplineBinning_size2 > 0) ? static_cast<int>(SplineBinning[0][0].size()) : 0;
1192 
1193  Settings->Branch("SplineBinning_size1", &SplineBinning_size1, "SplineBinning_size1/I");
1194  Settings->Branch("SplineBinning_size2", &SplineBinning_size2, "SplineBinning_size2/I");
1195  Settings->Branch("SplineBinning_size3", &SplineBinning_size3, "SplineBinning_size3/I");
1196 
1197  int SplineModeVecs_size1 = static_cast<int>(SplineModeVecs.size());
1198  int SplineModeVecs_size2 = (SplineModeVecs_size1 > 0) ? static_cast<int>(SplineModeVecs[0].size()) : 0;
1199  int SplineModeVecs_size3 = (SplineModeVecs_size2 > 0) ? static_cast<int>(SplineModeVecs[0][0].size()) : 0;
1200 
1201  Settings->Branch("SplineModeVecs_size1", &SplineModeVecs_size1, "SplineModeVecs_size1/I");
1202  Settings->Branch("SplineModeVecs_size2", &SplineModeVecs_size2, "SplineModeVecs_size2/I");
1203  Settings->Branch("SplineModeVecs_size3", &SplineModeVecs_size3, "SplineModeVecs_size3/I");
1204 
1205  std::vector<std::string> SampleNames_temp = SampleNames;
1206  Settings->Branch("SampleNames", &SampleNames_temp);
1207  std::vector<std::string> SampleTitles_temp = SampleTitles;
1208  Settings->Branch("SampleTitles", &SampleTitles_temp);
1209  std::vector<int> nSplineParams_temp = nSplineParams;
1210  Settings->Branch("nSplineParams", &nSplineParams_temp);
1211 
1212  Settings->Fill();
1213  SplineFile->cd();
1214  Settings->Write();
1215  delete Settings;
1216 }
1217 
1218 // *****************************************
1219 void BinnedSplineHandler::PrepareMonolithDir(std::unique_ptr<TFile>& SplineFile) const {
1220 // *****************************************
1221  TTree *MonolithTree = new TTree("MonolithTree", "MonolithTree");
1222  MonolithTree->Branch("manycoeff", manycoeff_arr, Form("manycoeff[%d]/%s", CoeffIndex * _nCoeff_, M3::float_t_str_repr));
1223  MonolithTree->Branch("isflatarray", isflatarray, Form("isflatarray[%d]/O", MonolithSize));
1224 
1225  std::vector<int> coeffindexvec_temp = coeffindexvec;
1226  MonolithTree->Branch("coeffindexvec", &coeffindexvec_temp);
1227  std::vector<int> uniquecoeffindices_temp = uniquecoeffindices;
1228  MonolithTree->Branch("uniquecoeffindices", &uniquecoeffindices_temp);
1229  std::vector<int> uniquesplinevec_Monolith_temp = uniquesplinevec_Monolith;
1230  MonolithTree->Branch("uniquesplinevec_Monolith", &uniquesplinevec_Monolith_temp);
1231  std::vector<int> UniqueSystIndices_temp = UniqueSystIndices;
1232  MonolithTree->Branch("UniqueSystIndices", &UniqueSystIndices_temp);
1233  MonolithTree->Branch("xcoeff", xcoeff_arr, Form("xcoeff[%d]/%s", CoeffIndex, M3::float_t_str_repr));
1234 
1235  MonolithTree->Fill();
1236  SplineFile->cd();
1237  MonolithTree->Write();
1238  delete MonolithTree;
1239 }
1240 
1241 // *****************************************
1242 void BinnedSplineHandler::PrepareIndexDir(std::unique_ptr<TFile>& SplineFile) const {
1243 // *****************************************
1244  // Create a TTree to store the data
1245  TTree *IndexTree = new TTree("IndexVec", "IndexVec");
1246  SplineIndex entry;
1247  IndexTree->Branch("SplineIndex", &entry);
1248  for (const auto& e : IndexVect) {
1249  entry = e;
1250  IndexTree->Fill();
1251  }
1252 
1253  SplineFile->cd();
1254  IndexTree->Write();
1255  delete IndexTree;
1256 }
1257 
1258 // *****************************************
1259 void BinnedSplineHandler::PrepareOtherInfoDir(std::unique_ptr<TFile>& SplineFile) const {
1260 // *****************************************
1261  // Create a new tree for SplineBinning data
1262  TTree *SplineBinningTree = new TTree("SplineBinningTree", "SplineBinningTree");
1263  std::vector<int> indices(3); // To store the 3D indices
1264  TAxis* axis = nullptr;
1265  SplineBinningTree->Branch("i", &indices[0], "i/I");
1266  SplineBinningTree->Branch("j", &indices[1], "j/I");
1267  SplineBinningTree->Branch("k", &indices[2], "k/I");
1268  SplineBinningTree->Branch("axis", "TAxis", &axis);
1269 
1270  // Fill the SplineBinningTree
1271  for (size_t i = 0; i < SplineBinning.size(); ++i) {
1272  for (size_t j = 0; j < SplineBinning[i].size(); ++j) {
1273  for (size_t k = 0; k < SplineBinning[i][j].size(); ++k) {
1274  axis = SplineBinning[i][j][k];
1275  indices[0] = static_cast<int>(i);
1276  indices[1] = static_cast<int>(j);
1277  indices[2] = static_cast<int>(k);
1278  SplineBinningTree->Fill();
1279  }
1280  }
1281  }
1282  SplineFile->cd();
1283  SplineBinningTree->Write();
1284  delete SplineBinningTree;
1285 
1286  std::vector<int> indices_mode(3); // to store 3D indices
1287  int mode_value;
1288 
1289  TTree *SplineModeTree = new TTree("SplineModeTree", "SplineModeTree");
1290  // Create branches for indices and value
1291  SplineModeTree->Branch("i", &indices_mode[0], "i/I");
1292  SplineModeTree->Branch("j", &indices_mode[1], "j/I");
1293  SplineModeTree->Branch("k", &indices_mode[2], "k/I");
1294  SplineModeTree->Branch("value", &mode_value, "value/I");
1295 
1296  // Fill the tree
1297  for (size_t i = 0; i < SplineModeVecs.size(); ++i) {
1298  for (size_t j = 0; j < SplineModeVecs[i].size(); ++j) {
1299  for (size_t k = 0; k < SplineModeVecs[i][j].size(); ++k) {
1300  indices_mode[0] = static_cast<int>(i);
1301  indices_mode[1] = static_cast<int>(j);
1302  indices_mode[2] = static_cast<int>(k);
1303  mode_value = SplineModeVecs[i][j][k];
1304  SplineModeTree->Fill();
1305  }
1306  }
1307  }
1308  // Write the tree to the file
1309  SplineFile->cd();
1310  SplineModeTree->Write();
1311  delete SplineModeTree;
1312 }
int GetSplineIndex(const std::vector< SplineIndex > &vec, const int sample, const int oscchan, const int syst, const int mode, const int var1bin, const int var2bin, const int var3bin)
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
Definition: Core.h:126
#define _MaCh3_Safe_Include_End_
#define MACH3LOG_CRITICAL
Definition: MaCh3Logger.h:38
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:34
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36
#define MACH3LOG_TRACE
Definition: MaCh3Logger.h:33
void CleanContainer(T &)
Base case: do nothing for non-pointer types.
void CleanVector(T &)
Base case: do nothing for non-vector types.
@ kSpline
For splined parameters (1D)
constexpr int _nCoeff_
KS: We store coefficients {y,b,c,d} in one array one by one, this is only to define it once rather th...
Definition: SplineCommon.h:18
@ kCoeffB
Coefficient B.
Definition: SplineCommon.h:26
@ kCoeffD
Coefficient D.
Definition: SplineCommon.h:28
@ kCoeffY
Coefficient Y.
Definition: SplineCommon.h:25
@ kCoeffC
Coefficient C.
Definition: SplineCommon.h:27
void ApplyKnotWeightCapTSpline3(TSpline3 *&Spline, const int splineParsIndex, ParameterHandlerGeneric *XsecCov)
EM: Apply capping to knot weight for specified spline parameter. param graph needs to have been set i...
Definition: SplineStructs.h:98
bool isFlat(TSpline3_red *&spl)
CW: Helper function used in the constructor, tests to see if the spline is flat.
TMacro YAMLtoTMacro(const YAML::Node &yaml_node, const std::string &name)
Convert a YAML node to a ROOT TMacro object.
Definition: YamlHelper.h:167
YAML::Node TMacroToYAML(const TMacro &macro)
KS: Convert a ROOT TMacro object to a YAML node.
Definition: YamlHelper.h:152
bool compareYAMLNodes(const YAML::Node &node1, const YAML::Node &node2, bool Mute=false)
Compare if yaml nodes are identical.
Definition: YamlHelper.h:186
void getSplineCoeff_SepMany(int splineindex, M3::float_t *&xArray, M3::float_t *&manyArray)
Rather work with spline coefficients in the splines, let's copy ND and use coefficient arrays.
virtual void FillSampleArray(const std::string &SampleTitle, const std::vector< std::string > &OscChanFileNames)
Loads and processes splines from ROOT files for a given sample.
bool * isflatarray
Need to keep track of which splines are flat and which aren't.
void LoadIndexDir(std::unique_ptr< TFile > &SplineFile)
KS: Load preprocessed Index.
int CountNumberOfLoadedSplines(bool NonFlat=false, int Verbosity=0)
Count how many splines we have.
ParameterHandlerGeneric * ParHandler
Pointer to covariance from which we get information about spline params.
void CalcSplineWeights() final
CPU based code which eval weight for each spline.
std::vector< std::vector< std::string > > SplineFileParPrefixNames
void LoadSettingsDir(std::unique_ptr< TFile > &SplineFile)
KS: Load preprocessed Settings.
std::vector< int > coeffindexvec
void cleanUpMemory()
Remove setup variables not needed for spline evaluations.
bool isValidSplineIndex(const std::string &SampleTitle, int iSyst, int iOscChan, int iMode, int iVar1, int iVar2, int iVar3) const
Ensure we have spline for a given bin.
void PrintBinning(TAxis *Axis) const
Print spline binning.
void PrepareSplineFile(std::string FileName) final
KS: Prepare spline file that can be used for fast loading.
void PrepForReweight()
Initialise flat structure.
void InvestigateMissingSplines() const
This function will find missing splines in file.
std::vector< int > nSplineParams
std::vector< std::vector< std::vector< int > > > SplineModeVecs
std::vector< int > nOscChans
M3::float_t * xcoeff_arr
x coefficients for each spline
std::vector< std::string > SampleTitles
void PrintSampleDetails(const std::string &SampleTitle) const
Print info like Sample ID of spline params etc.
std::vector< std::string > UniqueSystNames
name of each spline parameter
const M3::float_t * RetPointer(const int sample, const int oscchan, const int syst, const int mode, const int var1bin, const int var2bin, const int var3bin) const
get pointer to spline weight based on bin variables
std::vector< std::vector< SplineInterpolation > > SplineInterpolationTypes
spline interpolation types for each sample. These vectors are from a call to GetSplineInterpolationFr...
std::vector< SplineIndex > IndexVect
Variables related to determined which modes have splines and which piggy-back of other modes.
std::vector< std::vector< int > > GetEventSplines(const std::string &SampleTitle, int iOscChan, int EventMode, double Var1Val, double Var2Val, double Var3Val)
Return the splines which affect a given event.
void Evaluate() final
CW: This Eval should be used when using two separate x,{y,a,b,c,d} arrays to store the weights; proba...
std::vector< int > Dimensions
std::vector< int > uniquesplinevec_Monolith
Maps single spline object with single parameter.
void PrepareIndexDir(std::unique_ptr< TFile > &SplineFile) const
KS: Prepare Index Info within SplineFile.
void BuildSampleIndexingArray(const std::string &SampleTitle)
Only need 1 indexing array everything else interfaces with this to get binning properties.
std::vector< M3::float_t > weightvec_Monolith
Stores weight from spline evaluation for each single spline.
void AddSample(const std::string &SampleName, const std::string &SampleTitle, const std::vector< std::string > &OscChanFileNames, const std::vector< std::string > &SplineVarNames)
add oscillation channel to spline monolith
std::vector< TAxis * > FindSplineBinning(const std::string &FileName, const std::string &SampleTitle)
Grab histograms with spline binning.
std::vector< std::vector< std::string > > DimensionLabels
std::vector< std::vector< int > > StripDuplicatedModes(const std::vector< std::vector< int > > &InputVector) const
Creates an array to be filled with monolith indexes for each sample (allows for indexing between 7D b...
void LoadSplineFile(std::string FileName) final
KS: Load preprocessed spline file.
void PrepareMonolithDir(std::unique_ptr< TFile > &SplineFile) const
KS: Prepare Monolith Info within SplineFile.
BinnedSplineHandler(ParameterHandlerGeneric *xsec_, MaCh3Modes *Modes_)
Constructor.
void LoadMonolithDir(std::unique_ptr< TFile > &SplineFile)
KS: Load preprocessed Monolith.
std::vector< std::vector< std::vector< TAxis * > > > SplineBinning
std::vector< TSpline3_red * > splinevec_Monolith
holds each spline object before stripping into coefficient monolith
std::vector< int > uniquecoeffindices
Unique coefficient indices.
void PrepareOtherInfoDir(std::unique_ptr< TFile > &SplineFile) const
KS: Prepare Other Info within SplineFile.
void PrepareSettingsDir(std::unique_ptr< TFile > &SplineFile) const
KS: Prepare Settings Info within SplineFile.
MaCh3Modes * Modes
pointer to MaCh3 Mode from which we get spline suffix
void PrintArrayDetails(const std::string &SampleTitle) const
Print info like Sample ID of spline params etc.
std::vector< std::vector< int > > GlobalSystIndex
This holds the global spline index and is used to grab the current parameter value to evaluate spline...
virtual ~BinnedSplineHandler()
Destructor.
virtual std::vector< std::string > GetTokensFromSplineName(const std::string &FullSplineName)=0
std::vector< std::string > SampleNames
void TransferToMonolith()
flatten multidimensional spline array into proper monolith
std::vector< int > UniqueSystIndices
Global index of each spline param, it allows us to match spline ordering with global.
int GetSampleIndex(const std::string &SampleTitle) const
Get index of sample based on name.
M3::float_t * manycoeff_arr
ybcd coefficients for each spline
Custom exception class used throughout MaCh3.
KS: Class describing MaCh3 modes used in the analysis, it is being initialised from config.
Definition: MaCh3Modes.h:142
int GetNModes() const
KS: Get number of modes, keep in mind actual number is +1 greater due to unknown category.
Definition: MaCh3Modes.h:155
std::string GetSplineSuffixFromMaCh3Mode(const int Index)
DB: Get binned spline mode suffix from MaCh3 Mode.
Definition: MaCh3Modes.cpp:243
const M3::float_t * RetPointer(const int iParam) const
DB Pointer return to param position.
YAML::Node GetConfig() const
Getter to return a copy of the YAML node.
Class responsible for handling of systematic error parameters with different types defined in the con...
int GetNumParamsFromSampleName(const std::string &SampleName, const SystType Type) const
DB Grab the number of parameters for the relevant SampleName.
const std::vector< std::string > GetParsNamesFromSampleName(const std::string &SampleName, const SystType Type) const
DB Grab the parameter names for the relevant SampleName.
const std::vector< std::string > GetSplineParsNamesFromSampleName(const std::string &SampleName) const
DB Get spline parameters depending on given SampleName.
const std::vector< int > GetGlobalSystIndexFromSampleName(const std::string &SampleName, const SystType Type) const
DB Get spline parameters depending on given SampleName.
const std::vector< SplineInterpolation > GetSplineInterpolationFromSampleName(const std::string &SampleName) const
Get the interpolation types for splines affecting a particular SampleName.
const std::vector< std::vector< int > > GetSplineModeVecFromSampleName(const std::string &SampleName) const
DB Grab the Spline Modes for the relevant SampleName.
Base class for calculating weight from spline.
Definition: SplineBase.h:27
short int nParams
Number of parameters that have splines.
Definition: SplineBase.h:81
void FindSplineSegment()
CW:Code used in step by step reweighting, Find Spline Segment for each param.
Definition: SplineBase.cpp:44
short int * SplineSegments
Definition: SplineBase.h:77
std::vector< FastSplineInfo > SplineInfoArray
Definition: SplineBase.h:74
float * ParamValues
Store parameter values they are not in FastSplineInfo as in case of GPU we need to copy paste it to G...
Definition: SplineBase.h:79
void LoadFastSplineInfoDir(std::unique_ptr< TFile > &SplineFile)
KS: Load preprocessed FastSplineInfo.
Definition: SplineBase.cpp:167
void PrepareFastSplineInfoDir(std::unique_ptr< TFile > &SplineFile) const
KS: Prepare Fast Spline Info within SplineFile.
Definition: SplineBase.cpp:139
CW: Reduced TSpline3 class.
constexpr static const double _BAD_DOUBLE_
Default value used for double initialisation.
Definition: Core.h:53
double float_t
Definition: Core.h:37
TFile * Open(const std::string &Name, const std::string &Type, const std::string &File, const int Line)
Opens a ROOT file with the given name and mode.
constexpr static const char * float_t_str_repr
Definition: Core.h:40
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Definition: Core.h:55
constexpr T fmaf_t(T x, T y, T z)
Function template for fused multiply-add.
Definition: Core.h:45
void AddPath(std::string &FilePath)
Prepends the MACH3 environment path to FilePath if it is not already present.
Definition: Monitor.cpp:382
int int_t
Definition: Core.h:38
Flat representation of a spline index entry.
Definition: SplineCommon.h:33
int iSample
Sample index.
Definition: SplineCommon.h:41
int iMode
Mode index within a systematic.
Definition: SplineCommon.h:47
int value
Index into the flattened spline weight vector.
Definition: SplineCommon.h:39
int iVar2
Second kinematic bin index.
Definition: SplineCommon.h:51
int iVar3
Third kinematic bin index.
Definition: SplineCommon.h:53
int iOscChan
Oscillation channel index.
Definition: SplineCommon.h:43
int iSyst
Systematic parameter index.
Definition: SplineCommon.h:45
int iVar1
First kinematic bin index.
Definition: SplineCommon.h:49