1 #include <goofit/PDFs/basic/PolynomialPdf.h>
2 #include <goofit/Variable.h>
6 __device__ fptype device_Polynomial(fptype *evt, fptype *p, unsigned int *indices) {
7 // Structure is nP lowestdegree c1 c2 c3 nO o1
9 int numParams = RO_CACHE(indices[0]) + 1;
10 int lowestDegree = RO_CACHE(indices[1]);
12 fptype x = evt[RO_CACHE(indices[2 + RO_CACHE(indices[0])])];
15 for(int i = 2; i < numParams; ++i) {
16 ret += RO_CACHE(p[RO_CACHE(indices[i])]) * pow(x, lowestDegree + i - 2);
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]);
26 fptype x = evt[RO_CACHE(indices[2 + numParams])];
27 x -= RO_CACHE(p[RO_CACHE(indices[numParams])]);
30 for(int i = 2; i < numParams; ++i) {
31 ret += RO_CACHE(p[RO_CACHE(indices[i])]) * pow(x, lowestDegree + i - 2);
37 __device__ fptype device_MultiPolynomial(fptype *evt, fptype *p, unsigned int *indices) {
38 // Structure is nP, maxDegree, offset1, offset2, ..., coeff1, coeff2, ..., nO, o1, o2, ...
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.
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.
50 for(int i = 0; i < numObservables; ++i)
51 numBoxes *= maxDegree;
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.
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.
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...
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]);
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)
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;
99 // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
100 // printf("Final polynomial: %f\n", ret);
102 // if (0 > ret) ret = 0;
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;
110 // Constructor for single-variate polynomial, with optional zero point.
112 PolynomialPdf::PolynomialPdf(std::string n, Observable _x, std::vector<Variable> weights, unsigned int lowestDegree)
114 std::vector<unsigned int> pindices;
115 pindices.push_back(lowestDegree);
117 for(auto &weight : weights) {
118 pindices.push_back(registerParameter(weight));
121 GET_FUNCTION_ADDR(ptr_to_Polynomial);
123 initialize(pindices);
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)
130 , center(new Variable(x0)) {
131 std::vector<unsigned int> pindices;
132 pindices.push_back(lowestDegree);
134 for(auto &weight : weights) {
135 pindices.push_back(registerParameter(weight));
138 pindices.push_back(registerParameter(x0));
139 GET_FUNCTION_ADDR(ptr_to_OffsetPolynomial);
141 initialize(pindices);
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)
151 unsigned int numParameters = 1;
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)
158 for(unsigned int i = 0; i < obses.size(); ++i) {
159 registerObservable(obses[i]);
160 numParameters *= (maxDegree + 1 + i);
163 for(int i = observables.size(); i > 1; --i)
166 while(numParameters > coeffs.size()) {
168 sprintf(varName, "%s_extra_coeff_%i", getName().c_str(), static_cast<int>(coeffs.size()));
170 coeffs.emplace_back(varName, 0);
172 std::cout << "Warning: " << getName() << " created dummy variable " << varName
173 << " (fixed at zero) to account for all terms.\n";
176 while(offsets.size() < obses.size()) {
178 sprintf(varName, "%s_extra_offset_%i", getName().c_str(), static_cast<int>(offsets.size()));
179 offsets.emplace_back(varName, 0);
182 std::vector<unsigned int> pindices;
183 pindices.push_back(maxDegree);
185 for(auto &offset : offsets) {
186 pindices.push_back(registerParameter(offset));
189 for(auto &coeff : coeffs) {
190 pindices.push_back(registerParameter(coeff));
193 GET_FUNCTION_ADDR(ptr_to_MultiPolynomial);
194 initialize(pindices);
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];
203 hi -= host_params[indices[indices[0]]];
204 lo -= host_params[indices[indices[0]]];
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;
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";
228 unsigned int *indices = host_indices + parameters;
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.)
236 // Structure is nP lowestdegree c1 c2 c3 nO o1
237 if(coef < indices[1])
238 return 0; // Less than least power.
240 if(coef > indices[1] + (indices[0] - 1))
241 return 0; // Greater than max power.
243 fptype norm = normalize();
246 fptype param = host_params[indices[2 + coef - indices[1]]];
249 } // namespace GooFit