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