1 #include <goofit/PDFs/basic/SmoothHistogramPdf.h>
2 #include <goofit/Variable.h>
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;
10 __device__ int dev_powi(int base, int exp) {
13 for(int i = 0; i < exp; ++i)
19 __device__ fptype device_EvalHistogram(fptype *evt, fptype *p, unsigned int *indices) {
21 // nP smoothingIndex totalHistograms (limit1 step1 bins1) (limit2 step2 bins2) nO o1 o2
22 // where limit and step are indices into functorConstants.
24 int numVars = RO_CACHE(indices[RO_CACHE(indices[0]) + 1]);
25 int globalBinNumber = 0;
27 int myHistogramIndex = RO_CACHE(indices[2]); // 1 only used for smoothing
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])]);
38 currVariable -= lowerBound;
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]);
43 auto localBinNumber = static_cast<int>(floor(currVariable));
44 globalBinNumber += previous * localBinNumber;
45 previous *= indices[lowerBoundIdx + 2];
48 fptype *myHistogram = dev_smoothed_histograms[myHistogramIndex];
49 fptype ret = RO_CACHE(myHistogram[globalBinNumber]);
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]]);
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];
72 fptype otherBinsTotal = 0;
73 int numSurroundingBins = 0;
74 int otherBins = dev_powi(3, numVars);
76 for(int i = 0; i < otherBins; ++i) {
77 int currBin = globalBin;
78 int localPrevious = 1;
79 int trackingBin = globalBin;
80 bool offSomeAxis = false;
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;
88 currBin += offset * localPrevious;
89 localPrevious *= localNumBins;
91 int currVarBin = trackingBin % localNumBins;
92 trackingBin /= localNumBins;
94 if(currVarBin + offset < 0)
97 if(currVarBin + offset >= localNumBins)
101 if(currBin == globalBin)
105 continue; // Out of bounds
107 numSurroundingBins++;
109 otherBinsTotal += myHistogram[currBin];
112 centralValue += otherBinsTotal * smoothing;
113 centralValue /= (1 + numSurroundingBins * smoothing);
115 // if (7010 == globalBin) printf("Smoothing: %f %f %f %i %f\n", myHistogram[globalBin], otherBinsTotal,
116 // smoothing, numSurroundingBins, centralValue);
121 __device__ device_function_ptr ptr_to_EvalHistogram = device_EvalHistogram;
123 __host__ SmoothHistogramPdf::SmoothHistogramPdf(std::string n, BinnedDataSet *hist, Variable smoothing)
125 int numVars = hist->numVariables();
126 int numConstants = 2 * numVars;
127 registerConstants(numConstants);
128 host_constants = new fptype[numConstants];
131 std::vector<unsigned int> pindices;
132 pindices.push_back(registerParameter(smoothing));
133 pindices.push_back(totalHistograms);
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());
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();
150 unsigned int numbins = hist->getNumBins();
151 thrust::host_vector<fptype> host_histogram;
153 for(unsigned int i = 0; i < numbins; ++i) {
154 fptype curr = hist->getBinContent(i);
155 host_histogram.push_back(curr);
159 MEMCPY_TO_SYMBOL(functorConstants,
161 numConstants * sizeof(fptype),
162 cIndex * sizeof(fptype),
163 cudaMemcpyHostToDevice);
166 copyHistogramToDevice(host_histogram);
168 std::cout << "Warning: Empty histogram supplied to " << getName()
169 << " not copied to device. Expect copyHistogramToDevice call later.\n";
171 GET_FUNCTION_ADDR(ptr_to_EvalHistogram);
172 initialize(pindices);
175 fptype *pointerToFirst(thrust::device_vector<fptype> *hist) { return (&((*hist)[0])).get(); }
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]);
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);
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,
197 totalHistograms * sizeof(fptype *),
198 cudaMemcpyHostToDevice);
202 int expectedBins = 1;
204 for(Observable &observable : observables) {
205 expectedBins *= observable.getNumBins();
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";
214 __host__ fptype SmoothHistogramPdf::normalize() const {
216 smoother.parameters = parameters;
218 thrust::counting_iterator<int> binIndex(0);
219 thrust::transform(binIndex, binIndex + dev_base_histogram->size(), dev_smoothed_histogram->begin(), smoother);
221 // return totalEvents;
222 fptype ret = thrust::reduce(dev_smoothed_histogram->begin(), dev_smoothed_histogram->end());
224 for(unsigned int varIndex = 0; varIndex < observables.size(); ++varIndex) {
225 ret *= host_constants[2 * varIndex + 1]; // Bin size cached by constructor.
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;
233 } // namespace GooFit