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