MaCh3  2.8.0
Reference Guide
Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | List of all members
SplineBase Class Referenceabstract

Base class for calculating weight from spline. More...

#include <Splines/SplineBase.h>

Inheritance diagram for SplineBase:
[legend]
Collaboration diagram for SplineBase:
[legend]

Public Member Functions

 SplineBase (const bool Use_GPU=true)
 Constructor. More...
 
virtual ~SplineBase ()
 Destructor. More...
 
virtual void Evaluate ()=0
 CW: This Eval should be used when using two separate x,{y,a,b,c,d} arrays to store the weights; probably the best one here! Same thing but pass parameter spline segments instead of variations. More...
 
virtual std::string GetName () const
 Get class name. More...
 
short int GetNParams () const
 Get number of spline parameters. More...
 
virtual void PrepareSplineFile (std::string FileName)=0
 KS: Prepare spline file that can be used for fast loading. More...
 
virtual void LoadSplineFile (std::string FileName)=0
 KS: Load preprocessed spline file. More...
 
void SynchroniseMemTransfer () const
 KS: After calculations are done on GPU we copy memory to CPU. This operation is asynchronous meaning while memory is being copied some operations are being carried. Memory must be copied before actual reweight. This function make sure all has been copied. More...
 

Protected Member Functions

void FindSplineSegment ()
 CW:Code used in step by step reweighting, Find Spline Segment for each param. More...
 
virtual void CalcSplineWeights ()=0
 CPU based code which eval weight for each spline. More...
 
void PrepareFastSplineInfoDir (std::unique_ptr< TFile > &SplineFile) const
 KS: Prepare Fast Spline Info within SplineFile. More...
 
void LoadFastSplineInfoDir (std::unique_ptr< TFile > &SplineFile)
 KS: Load preprocessed FastSplineInfo. More...
 
void GetTF1Coeff (TF1_red *&spl, int &nPoints, float *&coeffs) const
 CW: Gets the polynomial coefficients for TF1. More...
 
void SetupSegments ()
 Since we find segment before actual reweight and sometimes we want to copy it to GPU we have different functionality depending if GPU or CPU. More...
 

Protected Attributes

std::vector< FastSplineInfo > SplineInfoArray
 
short int * SplineSegments
 
float * ParamValues
 Store parameter values they are not in FastSplineInfo as in case of GPU we need to copy paste it to GPU. More...
 
short int nParams
 Number of parameters that have splines. More...
 
short int _max_knots
 Max knots for production. More...
 
unsigned int NSplines_valid
 Number of valid splines. More...
 
SplineMonolithGPU * gpu_monolith
 KS: Store info about Spline monolith, this allow to obtain better step time. As all necessary information for spline weight calculation are here meaning better cache hits. More...
 
bool useGPU
 Whether to use GPU or not. More...
 

Private Member Functions

void CheckSegmentValidity (const M3::int_t i, const M3::int_t segment, const M3::float_t xvar, const std::vector< M3::float_t > &xPts) const
 Validates that the spline segment is correct for the given variation. More...
 

Detailed Description

Base class for calculating weight from spline.

Author
Dan Barrow
Kamil Skwarczynski

Definition at line 30 of file SplineBase.h.

Constructor & Destructor Documentation

◆ SplineBase()

SplineBase::SplineBase ( const bool  Use_GPU = true)

Constructor.

Definition at line 11 of file SplineBase.cpp.

11  {
12 // *****************************************
13  #ifdef MaCh3_CUDA
14  useGPU = Use_GPU;
15  if(useGPU) MACH3LOG_INFO("Using GPU version of {}", GetName());
16  gpu_monolith = nullptr;
17  #else
18  // if we don't have GPU simply
19  useGPU = false;
20  #endif
21 
22  NSplines_valid = 0;
23  nParams = 0;
24  _max_knots = 0;
25  SplineSegments = nullptr;
26  ParamValues = nullptr;
27 }
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
SplineMonolithGPU * gpu_monolith
KS: Store info about Spline monolith, this allow to obtain better step time. As all necessary informa...
Definition: SplineBase.h:120
unsigned int NSplines_valid
Number of valid splines.
Definition: SplineBase.h:117
short int nParams
Number of parameters that have splines.
Definition: SplineBase.h:113
virtual std::string GetName() const
Get class name.
Definition: SplineBase.h:41
short int _max_knots
Max knots for production.
Definition: SplineBase.h:115
short int * SplineSegments
Definition: SplineBase.h:109
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:111
bool useGPU
Whether to use GPU or not.
Definition: SplineBase.h:123

◆ ~SplineBase()

SplineBase::~SplineBase ( )
virtual

Destructor.

Definition at line 30 of file SplineBase.cpp.

30  {
31 // *****************************************
32 }

Member Function Documentation

◆ CalcSplineWeights()

virtual void SplineBase::CalcSplineWeights ( )
protectedpure virtual

CPU based code which eval weight for each spline.

Splines are stored using a flat monolithic structure. The monolith is organised as follows:

Spline 0
Segment 0: [ Y | B | C | D ]
Segment 1: [ Y | B | C | D ]
Segment 2: [ Y | B | C | D ]
Spline 1
Segment 0: [ Y | B | C | D ]
Segment 1: [ Y | B | C | D ]
Segment 2: [ Y | B | C | D ]
Spline 2
Segment 0: [ Y | B | C | D ]
Segment 1: [ Y | B | C | D ]
Segment 2: [ Y | B | C | D ]
...

Once coefficient are grabbed we calculate weight using:

weight = Y + B*dx + C*dx^2 + D*dx^3;

Implemented in PySplineBase, UnbinnedSplineHandler, and BinnedSplineHandler.

◆ CheckSegmentValidity()

void SplineBase::CheckSegmentValidity ( const M3::int_t  i,
const M3::int_t  segment,
const M3::float_t  xvar,
const std::vector< M3::float_t > &  xPts 
) const
private

Validates that the spline segment is correct for the given variation.

Parameters
iIndex of the spline in SplineInfoArray.
segmentThe segment index to validate.
xvarThe variation value being checked.
xPtsThe array of x-values for the spline.

Definition at line 35 of file SplineBase.cpp.

38  {
39 // *************************
40  if (xPts[segment] > xvar && segment != 0) {
41  MACH3LOG_ERROR("Found a segment which is _ABOVE_ the variation!");
42  MACH3LOG_ERROR("IT SHOULD ALWAYS BE BELOW! (except when segment 0)");
43  MACH3LOG_ERROR("Spline: {}", i);
44  MACH3LOG_ERROR("Found segment = {}", segment);
45  MACH3LOG_ERROR("Doing variation = {}", xvar);
46  MACH3LOG_ERROR("x in spline = {}", xPts[segment]);
47  for (size_t j = 0; j < xPts.size(); ++j) {
48  MACH3LOG_ERROR(" {} = {}", j, xPts[j]);
49  }
50  throw MaCh3Exception(__FILE__, __LINE__);
51  }
52 }
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
Custom exception class used throughout MaCh3.

◆ Evaluate()

virtual void SplineBase::Evaluate ( )
pure virtual

CW: This Eval should be used when using two separate x,{y,a,b,c,d} arrays to store the weights; probably the best one here! Same thing but pass parameter spline segments instead of variations.

Implemented in PySplineBase, UnbinnedSplineHandler, and BinnedSplineHandler.

◆ FindSplineSegment()

void SplineBase::FindSplineSegment ( )
protected

CW:Code used in step by step reweighting, Find Spline Segment for each param.

Definition at line 58 of file SplineBase.cpp.

58  {
59 // *************************
60  // Loop over the splines
61  //KS: Tried multithreading here with 48 splines and it is faster with one thread, maybe in future multithreading will be worth revisiting
62  for (M3::int_t i = 0; i < nParams; ++i)
63  {
64  const M3::int_t nPoints = SplineInfoArray[i].nPts;
65  const std::vector<M3::float_t>& xArray = SplineInfoArray[i].xPts;
66 
67  // Get the variation for this reconfigure for the ith parameter
68  const float xvar = float(*SplineInfoArray[i].splineParsPointer);
69  ParamValues[i] = xvar;
70 
71  // EM: if we have a parameter that has no response for any event (i.e. all splines have just one knot), then skip it and avoid a seg fault here
72  // In principle, such parameters shouldn't really be included in the first place, but with new det syst splines this
73  // could happen if say you were just running on one FHC run, then all RHC parameters would be flat and the code below would break.
74  if(xArray.size() == 0) continue;
75 
76  // The segment we're interested in (klow in ROOT code)
77  M3::int_t segment = 0;
78  M3::int_t kHigh = nPoints-1;
79  //KS: We expect new segment is very close to previous
80  const M3::int_t PreviousSegment = SplineInfoArray[i].CurrSegment;
81 
82  // If the variation is below the lowest saved spline point
83  if (xvar <= xArray[0]) {
84  segment = 0;
85  // If the variation is above the highest saved spline point
86  } else if (xvar >= xArray[nPoints-1]) {
87  //CW: Yes, the -2 is indeed correct, see TSpline.cxx:814 and //see: https://savannah.cern.ch/bugs/?71651
88  segment = kHigh;
89  //KS: It is quite probable the new segment is same as in previous step so try to avoid binary search, first we have to check if it is in bounds to avoid seg fault
90  } else if( xArray[PreviousSegment+1] > xvar && xvar >= xArray[PreviousSegment] ) {
91  segment = PreviousSegment;
92  // If the variation is between the maximum and minimum, perform a binary search
93  } else {
94  // The top point we've got
95  M3::int_t kHalf = 0;
96  // While there is still a difference in the points (we haven't yet found the segment)
97  // This is a binary search, incrementing segment and decrementing kHalf until we've found the segment
98  while (kHigh - segment > 1) {
99  // Increment the half-step
100  kHalf = M3::int_t((segment + kHigh)/2);
101  // If our variation is above the kHalf, set the segment to kHalf
102  if (xvar > xArray[kHalf]) {
103  segment = kHalf;
104  // Else move kHigh down
105  } else {
106  kHigh = kHalf;
107  }
108  } // End the while: we've now done our binary search
109  } // End the else: we've now found our point
110 
111  if (segment >= nPoints-1 && nPoints > 1) segment = nPoints-2;
112 
113  // CW: This way we avoid doing 1.2M+ binary searches on the GPU
114  // and literally just multiply lots of numbers together on the GPU without any algorithm
115  // Update the values and which segment it belongs to
116  SplineInfoArray[i].CurrSegment = segment;
117  SplineSegments[i] = short(SplineInfoArray[i].CurrSegment);
118 
119  #ifdef MACH3_DEBUG
120  CheckSegmentValidity(i, segment, xvar, SplineInfoArray[i].xPts);
121  #endif
122  } //end loop over params
123 }
void CheckSegmentValidity(const M3::int_t i, const M3::int_t segment, const M3::float_t xvar, const std::vector< M3::float_t > &xPts) const
Validates that the spline segment is correct for the given variation.
Definition: SplineBase.cpp:35
std::vector< FastSplineInfo > SplineInfoArray
Definition: SplineBase.h:106
int int_t
Definition: Core.h:38

◆ GetName()

virtual std::string SplineBase::GetName ( ) const
inlinevirtual

Get class name.

Reimplemented in UnbinnedSplineHandler, and PySplineBase.

Definition at line 41 of file SplineBase.h.

41 {return "SplineBase";};

◆ GetNParams()

short int SplineBase::GetNParams ( ) const
inline

Get number of spline parameters.

Definition at line 44 of file SplineBase.h.

44 {return nParams;};

◆ GetTF1Coeff()

void SplineBase::GetTF1Coeff ( TF1_red *&  spl,
int &  nPoints,
float *&  coeffs 
) const
protected

CW: Gets the polynomial coefficients for TF1.

Parameters
splpointer to TF1_red that will be checked
nPointsnumber of knots
coeffsArray holding coefficients for each knot

Definition at line 129 of file SplineBase.cpp.

129  {
130 // *****************************************
131  // Initialise all arrays to 1.0
132  for (int i = 0; i < _nTF1Coeff_; ++i) {
133  coeffs[i] = 0.0;
134  }
135 
136  // Get number of points in spline
137  nPoints = spl->GetSize();
138 
139  if(nPoints > _nTF1Coeff_)
140  {
141  MACH3LOG_ERROR("Too big number of points for TF1");
142  throw MaCh3Exception(__FILE__ , __LINE__ );
143  }
144  // TSpline3 can only take doubles, not floats
145  // But our GPU is slow with doubles, so need to cast to float
146  for (int i = 0; i < nPoints; i++) {
147  coeffs[i] = float(spl->GetParameter(M3::int_t(i)));
148  }
149  // The structure is now coeffs = {a,b,c,d,e}
150 }
constexpr int _nTF1Coeff_
KS: For TF1 we store at most 5 coefficients, we could make it more flexible but for now define it her...
Definition: SplineCommon.h:20
double GetParameter(M3::int_t Parameter) const
Get a parameter value.
int GetSize() const
Get the size.

◆ LoadFastSplineInfoDir()

void SplineBase::LoadFastSplineInfoDir ( std::unique_ptr< TFile > &  SplineFile)
protected

KS: Load preprocessed FastSplineInfo.

Parameters
FileFile from which we load new tree

Definition at line 181 of file SplineBase.cpp.

181  {
182 // *****************************************
183  TTree *FastSplineInfoTree = SplineFile->Get<TTree>("FastSplineInfoTree");
184  M3::int_t nPoints = 0;
185  float xtemp[20];
186  FastSplineInfoTree->SetBranchAddress("nPts", &nPoints);
187  FastSplineInfoTree->SetBranchAddress("xPts", &xtemp);
188 
189  if(nParams == 0){
190  MACH3LOG_WARN("Calling {} with {} number of params", __func__, nParams);
191  }
192  SplineInfoArray.resize(nParams);
193  for (M3::int_t i = 0; i < nParams; ++i) {
194  FastSplineInfoTree->GetEntry(i);
195 
196  // Fill the number of points
197  SplineInfoArray[i].nPts = nPoints;
198  if(nPoints == -999) continue;
199  SplineInfoArray[i].xPts.resize(SplineInfoArray[i].nPts);
200  for (M3::int_t k = 0; k < SplineInfoArray[i].nPts; ++k)
201  {
202  SplineInfoArray[i].xPts[k] = xtemp[k];
203  }
204  }
205 }
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36

◆ LoadSplineFile()

virtual void SplineBase::LoadSplineFile ( std::string  FileName)
pure virtual

KS: Load preprocessed spline file.

Parameters
FileNamePath to ROOT file with predefined reduced Spline Monolith

Implemented in UnbinnedSplineHandler, and BinnedSplineHandler.

◆ PrepareFastSplineInfoDir()

void SplineBase::PrepareFastSplineInfoDir ( std::unique_ptr< TFile > &  SplineFile) const
protected

KS: Prepare Fast Spline Info within SplineFile.

Parameters
FileFile to which we add new tree

Definition at line 153 of file SplineBase.cpp.

153  {
154 // *****************************************
155  TTree *FastSplineInfoTree = new TTree("FastSplineInfoTree", "FastSplineInfoTree");
156 
157  M3::int_t nPoints = 0;
158  float xtemp[20];
159  FastSplineInfoTree->Branch("nPts", &nPoints, "nPts/I");
160  FastSplineInfoTree->Branch("xPts", xtemp, "xPts[nPts]/F");
161 
162  for (M3::int_t i = 0; i < nParams; ++i)
163  {
164  nPoints = SplineInfoArray[i].nPts;
165 
166  for (M3::int_t k = 0; k < SplineInfoArray[i].nPts; ++k)
167  {
168  xtemp[k] = float(SplineInfoArray[i].xPts[k]);
169  }
170  FastSplineInfoTree->Fill();
171  }
172 
173  SplineFile->cd();
174  FastSplineInfoTree->Write();
175 
176  delete FastSplineInfoTree;
177 }

◆ PrepareSplineFile()

virtual void SplineBase::PrepareSplineFile ( std::string  FileName)
pure virtual

KS: Prepare spline file that can be used for fast loading.

Implemented in UnbinnedSplineHandler, and BinnedSplineHandler.

◆ SetupSegments()

void SplineBase::SetupSegments ( )
protected

Since we find segment before actual reweight and sometimes we want to copy it to GPU we have different functionality depending if GPU or CPU.

Definition at line 208 of file SplineBase.cpp.

208  {
209 // *****************************************
210  //KS: Since we are going to copy it each step use fancy CUDA memory allocation
211  #ifdef MaCh3_CUDA
212  if (useGPU) {
215  } else
216  #endif
217  {
218  SplineSegments = new short int[nParams]();
219  ParamValues = new float[nParams]();
220  }
221  //ETA - let this just be set as the first segment by default
222  for (M3::int_t j = 0; j < nParams; j++)
223  {
224  SplineSegments[j] = 0;
225  ParamValues[j] = -999;
226  }
227 }
__host__ void InitGPU_Vals(float **vals)
Allocate memory for spline segments.
__host__ void InitGPU_Segments(short int **segment)
Allocate memory for spline segments.

◆ SynchroniseMemTransfer()

void SplineBase::SynchroniseMemTransfer ( ) const

KS: After calculations are done on GPU we copy memory to CPU. This operation is asynchronous meaning while memory is being copied some operations are being carried. Memory must be copied before actual reweight. This function make sure all has been copied.

Definition at line 231 of file SplineBase.cpp.

231  {
232 //*********************************************************
233  #ifdef MaCh3_CUDA
234  if(useGPU) {
236  CudaCheckError();
237  }
238  #endif
239 }
__host__ void SynchroniseSplines()
Make sure all Cuda threads finished execution.
#define CudaCheckError()
Definition: gpuUtils.cuh:21

Member Data Documentation

◆ _max_knots

short int SplineBase::_max_knots
protected

Max knots for production.

Definition at line 115 of file SplineBase.h.

◆ gpu_monolith

SplineMonolithGPU* SplineBase::gpu_monolith
protected

KS: Store info about Spline monolith, this allow to obtain better step time. As all necessary information for spline weight calculation are here meaning better cache hits.

Definition at line 120 of file SplineBase.h.

◆ nParams

short int SplineBase::nParams
protected

Number of parameters that have splines.

Definition at line 113 of file SplineBase.h.

◆ NSplines_valid

unsigned int SplineBase::NSplines_valid
protected

Number of valid splines.

Definition at line 117 of file SplineBase.h.

◆ ParamValues

float* SplineBase::ParamValues
protected

Store parameter values they are not in FastSplineInfo as in case of GPU we need to copy paste it to GPU.

Definition at line 111 of file SplineBase.h.

◆ SplineInfoArray

std::vector<FastSplineInfo> SplineBase::SplineInfoArray
protected

Array of FastSplineInfo structs: keeps information on each spline for fast evaluation Method identical to TSpline3::Eval(double) but faster because less operations

Definition at line 106 of file SplineBase.h.

◆ SplineSegments

short int* SplineBase::SplineSegments
protected

Store currently found segment they are not in FastSplineInfo as in case of GPU we need to copy paste it to GPU

Warning
this is being used sometimes by GPU, therefore must be raw pointer!

Definition at line 109 of file SplineBase.h.

◆ useGPU

bool SplineBase::useGPU
protected

Whether to use GPU or not.

Definition at line 123 of file SplineBase.h.


The documentation for this class was generated from the following files: