GooFit  v2.1.3
SmoothHistogramPdf.cu
Go to the documentation of this file.
1 #include <goofit/PDFs/basic/SmoothHistogramPdf.h>
2 #include <goofit/Variable.h>
3 
4 namespace GooFit {
5 
6 __constant__ fptype *dev_base_histograms[100]; // Multiple histograms for the case of multiple PDFs
7 __constant__ fptype *dev_smoothed_histograms[100];
8 unsigned int SmoothHistogramPdf::totalHistograms = 0;
9 
10 __device__ int dev_powi(int base, int exp) {
11  int ret = 1;
12 
13  for(int i = 0; i < exp; ++i)
14  ret *= base;
15 
16  return ret;
17 }
18 
19 __device__ fptype device_EvalHistogram(fptype *evt, fptype *p, unsigned int *indices) {
20  // Structure is
21  // nP smoothingIndex totalHistograms (limit1 step1 bins1) (limit2 step2 bins2) nO o1 o2
22  // where limit and step are indices into functorConstants.
23 
24  int numVars = RO_CACHE(indices[RO_CACHE(indices[0]) + 1]);
25  int globalBinNumber = 0;
26  int previous = 1;
27  int myHistogramIndex = RO_CACHE(indices[2]); // 1 only used for smoothing
28 
29  for(int i = 0; i < numVars; ++i) {
30  int varIndex = RO_CACHE(indices[RO_CACHE(indices[0]) + 2 + i]);
31  int lowerBoundIdx = 3 * (i + 1);
32  // if (gpuDebug & 1) printf("[%i, %i] Smoothed: %i %i %i\n", BLOCKIDX, THREADIDX, i, varIndex,
33  // indices[varIndex]);
34  fptype currVariable = evt[varIndex];
35  fptype lowerBound = RO_CACHE(functorConstants[RO_CACHE(indices[lowerBoundIdx + 0])]);
36  fptype step = RO_CACHE(functorConstants[RO_CACHE(indices[lowerBoundIdx + 1])]);
37 
38  currVariable -= lowerBound;
39  currVariable /= step;
40  // if (gpuDebug & 1) printf("[%i, %i] Smoothed: %i %i %f %f %f %f\n", BLOCKIDX, THREADIDX, i, varIndex,
41  // currVariable, lowerBound, step, evt[varIndex]);
42 
43  auto localBinNumber = static_cast<int>(floor(currVariable));
44  globalBinNumber += previous * localBinNumber;
45  previous *= indices[lowerBoundIdx + 2];
46  }
47 
48  fptype *myHistogram = dev_smoothed_histograms[myHistogramIndex];
49  fptype ret = RO_CACHE(myHistogram[globalBinNumber]);
50 
51  // if ((gpuDebug & 1) && (evt[8] < 0.5) && (paramIndices + debugParamIndex == indices)) printf("Smoothed: %f %f %f
52  // %i %f\n", evt[6], evt[7], myHistogram[globalBinNumber], globalBinNumber,
53  // dev_base_histograms[myHistogramIndex][globalBinNumber]);
54  // if (gpuDebug & 1) printf("Smoothed: %f %f %f %i %f\n", evt[0], evt[1], myHistogram[globalBinNumber],
55  // globalBinNumber, dev_base_histograms[myHistogramIndex][globalBinNumber]);
56  // if (gpuDebug & 1) printf("Smoothed: %f %f %f %i %f %f\n", evt[0], evt[1], ret, globalBinNumber,
57  // dev_base_histograms[myHistogramIndex][globalBinNumber], p[indices[1]]);
58  return ret;
59 }
60 
61 struct Smoother {
62  int parameters;
63 
64  __device__ fptype operator()(int globalBin) {
65  unsigned int *indices = paramIndices + parameters;
66  int numVars = RO_CACHE(indices[RO_CACHE(indices[0]) + 1]);
67  fptype smoothing = RO_CACHE(cudaArray[RO_CACHE(indices[1])]);
68  int histIndex = RO_CACHE(indices[2]);
69  fptype *myHistogram = dev_base_histograms[histIndex];
70  fptype centralValue = myHistogram[globalBin];
71 
72  fptype otherBinsTotal = 0;
73  int numSurroundingBins = 0;
74  int otherBins = dev_powi(3, numVars);
75 
76  for(int i = 0; i < otherBins; ++i) {
77  int currBin = globalBin;
78  int localPrevious = 1;
79  int trackingBin = globalBin;
80  bool offSomeAxis = false;
81 
82  for(int v = 0; v < numVars; ++v) {
83  // int lowerBoundIdx = 3*(i+1);
84  // int localNumBins = indices[6 + v*4];
85  int localNumBins = RO_CACHE(indices[3 * (v + 1) + 2]);
86  int offset = ((i / dev_powi(3, v)) % 3) - 1;
87 
88  currBin += offset * localPrevious;
89  localPrevious *= localNumBins;
90 
91  int currVarBin = trackingBin % localNumBins;
92  trackingBin /= localNumBins;
93 
94  if(currVarBin + offset < 0)
95  offSomeAxis = true;
96 
97  if(currVarBin + offset >= localNumBins)
98  offSomeAxis = true;
99  }
100 
101  if(currBin == globalBin)
102  continue;
103 
104  if(offSomeAxis)
105  continue; // Out of bounds
106 
107  numSurroundingBins++;
108 
109  otherBinsTotal += myHistogram[currBin];
110  }
111 
112  centralValue += otherBinsTotal * smoothing;
113  centralValue /= (1 + numSurroundingBins * smoothing);
114 
115  // if (7010 == globalBin) printf("Smoothing: %f %f %f %i %f\n", myHistogram[globalBin], otherBinsTotal,
116  // smoothing, numSurroundingBins, centralValue);
117  return centralValue;
118  }
119 };
120 
121 __device__ device_function_ptr ptr_to_EvalHistogram = device_EvalHistogram;
122 
123 __host__ SmoothHistogramPdf::SmoothHistogramPdf(std::string n, BinnedDataSet *hist, Variable smoothing)
124  : GooPdf(n) {
125  int numVars = hist->numVariables();
126  int numConstants = 2 * numVars;
127  registerConstants(numConstants);
128  host_constants = new fptype[numConstants];
129  totalEvents = 0;
130 
131  std::vector<unsigned int> pindices;
132  pindices.push_back(registerParameter(smoothing));
133  pindices.push_back(totalHistograms);
134 
135  int varIndex = 0;
136 
137  for(Observable var : hist->getObservables()) {
138  registerObservable(var);
139  // pindices.push_back((*var)->index);
140  pindices.push_back(cIndex + 2 * varIndex + 0);
141  pindices.push_back(cIndex + 2 * varIndex + 1);
142  pindices.push_back(var.getNumBins());
143 
144  host_constants[2 * varIndex + 0] = var.getLowerLimit(); // NB, do not put cIndex here, it is accounted for by
145  // the offset in MEMCPY_TO_SYMBOL below.
146  host_constants[2 * varIndex + 1] = var.getBinSize();
147  varIndex++;
148  }
149 
150  unsigned int numbins = hist->getNumBins();
151  thrust::host_vector<fptype> host_histogram;
152 
153  for(unsigned int i = 0; i < numbins; ++i) {
154  fptype curr = hist->getBinContent(i);
155  host_histogram.push_back(curr);
156  totalEvents += curr;
157  }
158 
159  MEMCPY_TO_SYMBOL(functorConstants,
160  host_constants,
161  numConstants * sizeof(fptype),
162  cIndex * sizeof(fptype),
163  cudaMemcpyHostToDevice);
164 
165  if(totalEvents > 0)
166  copyHistogramToDevice(host_histogram);
167  else
168  std::cout << "Warning: Empty histogram supplied to " << getName()
169  << " not copied to device. Expect copyHistogramToDevice call later.\n";
170 
171  GET_FUNCTION_ADDR(ptr_to_EvalHistogram);
172  initialize(pindices);
173 }
174 
175 fptype *pointerToFirst(thrust::device_vector<fptype> *hist) { return (&((*hist)[0])).get(); }
176 
177 fptype *pointerToFirst(thrust::host_vector<fptype> *hist) {
178  // (*hist) is the host_vector.
179  // (*hist)[0] is a 'reference' - Thrust class, not ordinary C++ reference -
180  // to the first element of the vector.
181  // &((*hist)[0]) is a 'Pointer', as defined by the host_vector, to the location
182  // of the 'reference'. Fortunately this is by default fptype*!
183  return &((*hist)[0]);
184 }
185 
186 __host__ void SmoothHistogramPdf::copyHistogramToDevice(thrust::host_vector<fptype> &host_histogram) {
187  dev_base_histogram = new thrust::device_vector<fptype>(host_histogram);
188  dev_smoothed_histogram = new thrust::device_vector<fptype>(host_histogram);
189  static fptype *dev_address[1];
190  dev_address[0] = pointerToFirst(dev_base_histogram);
191  MEMCPY_TO_SYMBOL(
192  dev_base_histograms, dev_address, sizeof(fptype *), totalHistograms * sizeof(fptype *), cudaMemcpyHostToDevice);
193  dev_address[0] = pointerToFirst(dev_smoothed_histogram);
194  MEMCPY_TO_SYMBOL(dev_smoothed_histograms,
195  dev_address,
196  sizeof(fptype *),
197  totalHistograms * sizeof(fptype *),
198  cudaMemcpyHostToDevice);
199 
200  totalHistograms++;
201 
202  int expectedBins = 1;
203 
204  for(Observable &observable : observables) {
205  expectedBins *= observable.getNumBins();
206  }
207 
208  if(expectedBins != host_histogram.size()) {
209  std::cout << "Warning: Histogram supplied to " << getName() << " has " << host_histogram.size()
210  << " bins, expected " << expectedBins << " - may indicate a problem.\n";
211  }
212 }
213 
214 __host__ fptype SmoothHistogramPdf::normalize() const {
215  Smoother smoother;
216  smoother.parameters = parameters;
217 
218  thrust::counting_iterator<int> binIndex(0);
219  thrust::transform(binIndex, binIndex + dev_base_histogram->size(), dev_smoothed_histogram->begin(), smoother);
220 
221  // return totalEvents;
222  fptype ret = thrust::reduce(dev_smoothed_histogram->begin(), dev_smoothed_histogram->end());
223 
224  for(unsigned int varIndex = 0; varIndex < observables.size(); ++varIndex) {
225  ret *= host_constants[2 * varIndex + 1]; // Bin size cached by constructor.
226  }
227 
228  // if (cpuDebug & 1) std::cout << "Normalising " << getName() << " " << host_params[host_indices[parameters + 1]] <<
229  // " " << ret << std::endl;
230  host_normalisation[parameters] = 1.0 / ret;
231  return ret;
232 }
233 } // namespace GooFit