GooFit  v2.1.3
PolynomialPdf.cu
Go to the documentation of this file.
1 #include <goofit/PDFs/basic/PolynomialPdf.h>
2 #include <goofit/Variable.h>
3 
4 namespace GooFit {
5 
6 __device__ fptype device_Polynomial(fptype *evt, fptype *p, unsigned int *indices) {
7  // Structure is nP lowestdegree c1 c2 c3 nO o1
8 
9  int numParams = RO_CACHE(indices[0]) + 1;
10  int lowestDegree = RO_CACHE(indices[1]);
11 
12  fptype x = evt[RO_CACHE(indices[2 + RO_CACHE(indices[0])])];
13  fptype ret = 0;
14 
15  for(int i = 2; i < numParams; ++i) {
16  ret += RO_CACHE(p[RO_CACHE(indices[i])]) * pow(x, lowestDegree + i - 2);
17  }
18 
19  return ret;
20 }
21 
22 __device__ fptype device_OffsetPolynomial(fptype *evt, fptype *p, unsigned int *indices) {
23  int numParams = RO_CACHE(indices[0]);
24  int lowestDegree = RO_CACHE(indices[1]);
25 
26  fptype x = evt[RO_CACHE(indices[2 + numParams])];
27  x -= RO_CACHE(p[RO_CACHE(indices[numParams])]);
28  fptype ret = 0;
29 
30  for(int i = 2; i < numParams; ++i) {
31  ret += RO_CACHE(p[RO_CACHE(indices[i])]) * pow(x, lowestDegree + i - 2);
32  }
33 
34  return ret;
35 }
36 
37 __device__ fptype device_MultiPolynomial(fptype *evt, fptype *p, unsigned int *indices) {
38  // Structure is nP, maxDegree, offset1, offset2, ..., coeff1, coeff2, ..., nO, o1, o2, ...
39 
40  int numObservables = RO_CACHE(indices[RO_CACHE(indices[0]) + 1]);
41  int maxDegree = RO_CACHE(indices[1]) + 1;
42  // Only appears in construction (maxDegree + 1) or (x > maxDegree), so
43  // may as well add the one and use >= instead.
44 
45  // Technique is to iterate over the full n-dimensional box, skipping matrix elements
46  // whose sum of indices is greater than maxDegree. Notice that this is increasingly
47  // inefficient as n grows, since a larger proportion of boxes will be skipped.
48  int numBoxes = 1;
49 
50  for(int i = 0; i < numObservables; ++i)
51  numBoxes *= maxDegree;
52 
53  int coeffNumber = 2 + numObservables; // Index of first coefficient is 2 + nO, not 1 + nO, due to maxDegree. (nO
54  // comes from offsets.)
55  fptype ret = RO_CACHE(p[RO_CACHE(indices[coeffNumber++])]); // Coefficient of constant term.
56 
57  for(int i = 1; i < numBoxes;
58  ++i) { // Notice skip of inmost 'box' in the pyramid, corresponding to all powers zero, already accounted for.
59  fptype currTerm = 1;
60  int currIndex = i;
61  int sumOfIndices = 0;
62 
63  // if ((gpuDebug & 1) && (THREADIDX == 50) && (BLOCKIDX == 3))
64  // if ((BLOCKIDX == internalDebug1) && (THREADIDX == internalDebug2))
65  // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
66  // printf("[%i, %i] Start box %i %f %f:\n", BLOCKIDX, THREADIDX, i, ret, evt[8]);
67  for(int j = 0; j < numObservables; ++j) {
68  fptype x = RO_CACHE(evt[RO_CACHE(indices[2 + RO_CACHE(indices[0]) + j])]); // x, y, z...
69  fptype offset = RO_CACHE(p[RO_CACHE(indices[2 + j])]); // x0, y0, z0...
70  x -= offset;
71  int currPower = currIndex % maxDegree;
72  currIndex /= maxDegree;
73  currTerm *= pow(x, currPower);
74  sumOfIndices += currPower;
75  // if ((gpuDebug & 1) && (THREADIDX == 50) && (BLOCKIDX == 3))
76  // if ((BLOCKIDX == internalDebug1) && (THREADIDX == internalDebug2))
77  // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
78  // printf(" [%f -> %f^%i = %f] (%i %i) \n", evt[indices[2 + indices[0] + j]], x, currPower, pow(x,
79  // currPower), sumOfIndices, indices[2 + indices[0] + j]);
80  }
81 
82  // if ((gpuDebug & 1) && (THREADIDX == 50) && (BLOCKIDX == 3))
83  // if ((BLOCKIDX == internalDebug1) && (THREADIDX == internalDebug2))
84  // printf(") End box %i\n", i);
85  // All threads should hit this at the same time and with the same result. No branching.
86  if(sumOfIndices >= maxDegree)
87  continue;
88 
89  fptype coefficient = RO_CACHE(p[RO_CACHE(indices[coeffNumber++])]); // Coefficient from MINUIT
90  // if ((gpuDebug & 1) && (THREADIDX == 50) && (BLOCKIDX == 3))
91  // if ((BLOCKIDX == internalDebug1) && (THREADIDX == internalDebug2))
92  // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
93  // printf("Box %i contributes %f * %f = %f -> %f\n", i, currTerm, p[indices[coeffNumber - 1]],
94  // coefficient*currTerm, (ret + coefficient*currTerm));
95  currTerm *= coefficient;
96  ret += currTerm;
97  }
98 
99  // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
100  // printf("Final polynomial: %f\n", ret);
101 
102  // if (0 > ret) ret = 0;
103  return ret;
104 }
105 
106 __device__ device_function_ptr ptr_to_Polynomial = device_Polynomial;
107 __device__ device_function_ptr ptr_to_OffsetPolynomial = device_OffsetPolynomial;
108 __device__ device_function_ptr ptr_to_MultiPolynomial = device_MultiPolynomial;
109 
110 // Constructor for single-variate polynomial, with optional zero point.
111 __host__
112 PolynomialPdf::PolynomialPdf(std::string n, Observable _x, std::vector<Variable> weights, unsigned int lowestDegree)
113  : GooPdf(n, _x) {
114  std::vector<unsigned int> pindices;
115  pindices.push_back(lowestDegree);
116 
117  for(auto &weight : weights) {
118  pindices.push_back(registerParameter(weight));
119  }
120 
121  GET_FUNCTION_ADDR(ptr_to_Polynomial);
122 
123  initialize(pindices);
124 }
125 
126 // Constructor for single-variate polynomial, with optional zero point.
127 __host__ PolynomialPdf::PolynomialPdf(
128  std::string n, Observable _x, std::vector<Variable> weights, Variable x0, unsigned int lowestDegree)
129  : GooPdf(n, _x)
130  , center(new Variable(x0)) {
131  std::vector<unsigned int> pindices;
132  pindices.push_back(lowestDegree);
133 
134  for(auto &weight : weights) {
135  pindices.push_back(registerParameter(weight));
136  }
137 
138  pindices.push_back(registerParameter(x0));
139  GET_FUNCTION_ADDR(ptr_to_OffsetPolynomial);
140 
141  initialize(pindices);
142 }
143 
144 // Constructor for multivariate polynomial.
145 __host__ PolynomialPdf::PolynomialPdf(std::string n,
146  std::vector<Observable> obses,
147  std::vector<Variable> coeffs,
148  std::vector<Variable> offsets,
149  unsigned int maxDegree)
150  : GooPdf(n) {
151  unsigned int numParameters = 1;
152 
153  // For 1 observable, equal to n = maxDegree + 1.
154  // For two, n*(n+1)/2, ie triangular number. This generalises:
155  // 3: Pyramidal number n*(n+1)*(n+2)/(3*2)
156  // 4: Hyperpyramidal number n*(n+1)*(n+2)*(n+3)/(4*3*2)
157  // ...
158  for(unsigned int i = 0; i < obses.size(); ++i) {
159  registerObservable(obses[i]);
160  numParameters *= (maxDegree + 1 + i);
161  }
162 
163  for(int i = observables.size(); i > 1; --i)
164  numParameters /= i;
165 
166  while(numParameters > coeffs.size()) {
167  char varName[100];
168  sprintf(varName, "%s_extra_coeff_%i", getName().c_str(), static_cast<int>(coeffs.size()));
169 
170  coeffs.emplace_back(varName, 0);
171 
172  std::cout << "Warning: " << getName() << " created dummy variable " << varName
173  << " (fixed at zero) to account for all terms.\n";
174  }
175 
176  while(offsets.size() < obses.size()) {
177  char varName[100];
178  sprintf(varName, "%s_extra_offset_%i", getName().c_str(), static_cast<int>(offsets.size()));
179  offsets.emplace_back(varName, 0);
180  }
181 
182  std::vector<unsigned int> pindices;
183  pindices.push_back(maxDegree);
184 
185  for(auto &offset : offsets) {
186  pindices.push_back(registerParameter(offset));
187  }
188 
189  for(auto &coeff : coeffs) {
190  pindices.push_back(registerParameter(coeff));
191  }
192 
193  GET_FUNCTION_ADDR(ptr_to_MultiPolynomial);
194  initialize(pindices);
195 }
196 
197 __host__ fptype PolynomialPdf::integrate(fptype lo, fptype hi) const {
198  // This is *still* wrong. (13 Feb 2013.)
199  unsigned int *indices = host_indices + parameters;
200  fptype lowestDegree = indices[1];
201 
202  if(center) {
203  hi -= host_params[indices[indices[0]]];
204  lo -= host_params[indices[indices[0]]];
205  }
206 
207  fptype ret = 0;
208 
209  for(int i = 2; i < indices[0] + (center ? 0 : 1); ++i) {
210  fptype powerPlusOne = lowestDegree + i - 2;
211  fptype curr = pow(hi, powerPlusOne);
212  curr -= pow(lo, powerPlusOne);
213  curr /= powerPlusOne;
214  ret += host_params[indices[i]] * curr;
215  }
216 
217  return ret;
218 }
219 
220 __host__ fptype PolynomialPdf::getCoefficient(int coef) const {
221  // NB! This function only works for single polynomials.
222  if(1 != observables.size()) {
223  std::cout << "Warning: getCoefficient method of PolynomialPdf not implemented for multi-dimensional "
224  "polynomials. Returning zero, which is very likely wrong.\n";
225  return 0;
226  }
227 
228  unsigned int *indices = host_indices + parameters;
229 
230  // True function is, say, ax^2 + bx + c.
231  // We express this as (a'x^2 + b'x + c')*N.
232  // So to get the true coefficient, multiply the internal
233  // one by the normalisation. (In non-PDF cases the normalisation
234  // equals one, which gives the same result.)
235 
236  // Structure is nP lowestdegree c1 c2 c3 nO o1
237  if(coef < indices[1])
238  return 0; // Less than least power.
239 
240  if(coef > indices[1] + (indices[0] - 1))
241  return 0; // Greater than max power.
242 
243  fptype norm = normalize();
244  norm = (1.0 / norm);
245 
246  fptype param = host_params[indices[2 + coef - indices[1]]];
247  return norm * param;
248 }
249 } // namespace GooFit