1 #include <goofit/Error.h>
2 #include <goofit/PDFs/combine/AddPdf.h>
3 #include <goofit/detail/ThrustOverride.h>
5 #include <thrust/iterator/constant_iterator.h>
6 #include <thrust/transform_reduce.h>
14 __device__ fptype device_AddPdfs(fptype *evt, fptype *p, unsigned int *indices) {
15 int numParameters = RO_CACHE(indices[0]);
17 fptype totalWeight = 0;
19 for(int i = 1; i < numParameters - 3; i += 3) {
20 totalWeight += RO_CACHE(p[RO_CACHE(indices[i + 2])]);
21 fptype curr = callFunction(evt, RO_CACHE(indices[i]), RO_CACHE(indices[i + 1]));
22 fptype weight = RO_CACHE(p[RO_CACHE(indices[i + 2])]);
23 ret += weight * curr * normalisationFactors[RO_CACHE(indices[i + 1])];
25 // if ((gpuDebug & 1) && (0 == THREADIDX) && (0 == BLOCKIDX))
26 // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
27 // printf("Add comp %i: %f * %f * %f = %f (%f)\n", i, weight, curr, normalisationFactors[indices[i+1]],
28 // weight*curr*normalisationFactors[indices[i+1]], ret);
31 // numParameters does not count itself. So the array structure for two functions is
33 // in which nP = 5. Therefore the parameter index for the last function pointer is nP, and the function index is
35 // fptype last = (*(reinterpret_cast<device_function_ptr>(device_function_table[indices[numParameters-1]])))(evt, p,
36 // paramIndices + indices[numParameters]);
37 fptype last = callFunction(evt, RO_CACHE(indices[numParameters - 1]), RO_CACHE(indices[numParameters]));
38 ret += (1 - totalWeight) * last * normalisationFactors[RO_CACHE(indices[numParameters])];
40 // if ((THREADIDX < 50) && (isnan(ret))) printf("NaN final component %f %f\n", last, totalWeight);
42 // if ((gpuDebug & 1) && (0 == THREADIDX) && (0 == BLOCKIDX))
43 // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
44 // printf("Add final: %f * %f * %f = %f (%f)\n", (1 - totalWeight), last,
45 // normalisationFactors[indices[numParameters]], (1 - totalWeight) *last*
46 // normalisationFactors[indices[numParameters]], ret);
51 __device__ fptype device_AddPdfsExt(fptype *evt, fptype *p, unsigned int *indices) {
52 // numParameters does not count itself. So the array structure for two functions is
56 int numParameters = RO_CACHE(indices[0]);
58 fptype totalWeight = 0;
60 for(int i = 1; i < numParameters; i += 3) {
61 // fptype curr = (*(reinterpret_cast<device_function_ptr>(device_function_table[indices[i]])))(evt, p,
62 // paramIndices + indices[i+1]);
63 fptype curr = callFunction(evt, RO_CACHE(indices[i]), RO_CACHE(indices[i + 1]));
64 fptype weight = RO_CACHE(p[RO_CACHE(indices[i + 2])]);
65 ret += weight * curr * normalisationFactors[RO_CACHE(indices[i + 1])];
67 totalWeight += weight;
68 // if ((gpuDebug & 1) && (THREADIDX == 0) && (0 == BLOCKIDX))
69 // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
70 // printf("AddExt: %i %E %f %f %f %f %f %f\n", i, curr, weight, ret, totalWeight,
71 // normalisationFactors[indices[i+1]], evt[0], evt[8]);
75 // if ((1 > (int) floor(0.5 + evt[8])) && (gpuDebug & 1) && (paramIndices + debugParamIndex == indices))
76 // if ((gpuDebug & 1) && (THREADIDX == 0) && (0 == BLOCKIDX))
77 // printf("AddExt result: %f\n", ret);
82 __device__ device_function_ptr ptr_to_AddPdfs = device_AddPdfs;
83 __device__ device_function_ptr ptr_to_AddPdfsExt = device_AddPdfsExt;
85 AddPdf::AddPdf(std::string n, std::vector<Variable> weights, std::vector<PdfBase *> comps)
88 if(weights.size() != comps.size() && (weights.size() + 1) != comps.size())
89 throw GooFit::GeneralError("Size of weights {} (+1) != comps {}", weights.size(), comps.size());
91 // Indices stores (function index)(function parameter index)(weight index) triplet for each component.
92 // Last component has no weight index unless function is extended.
93 for(PdfBase *p : comps) {
94 components.push_back(p);
95 if(components.back() == nullptr)
96 throw GooFit::GeneralError("Invalid component");
99 observables = getObservables();
101 std::vector<unsigned int> pindices;
103 for(unsigned int w = 0; w < weights.size(); ++w) {
104 if(components[w] == nullptr)
105 throw GooFit::GeneralError("Invalid component");
106 pindices.push_back(components[w]->getFunctionIndex());
107 pindices.push_back(components[w]->getParameterIndex());
108 pindices.push_back(registerParameter(weights[w]));
111 if(components.back() == nullptr)
112 throw GooFit::GeneralError("Invalid component");
114 if(weights.size() < components.size()) {
115 pindices.push_back(components.back()->getFunctionIndex());
116 pindices.push_back(components.back()->getParameterIndex());
121 GET_FUNCTION_ADDR(ptr_to_AddPdfsExt);
123 GET_FUNCTION_ADDR(ptr_to_AddPdfs);
126 initialize(pindices);
129 AddPdf::AddPdf(std::string n, Variable frac1, PdfBase *func1, PdfBase *func2)
132 // Special-case constructor for common case of adding two functions.
133 components.push_back(func1);
134 components.push_back(func2);
135 observables = getObservables();
137 std::vector<unsigned int> pindices;
138 pindices.push_back(func1->getFunctionIndex());
139 pindices.push_back(func1->getParameterIndex());
140 pindices.push_back(registerParameter(frac1));
142 pindices.push_back(func2->getFunctionIndex());
143 pindices.push_back(func2->getParameterIndex());
145 GET_FUNCTION_ADDR(ptr_to_AddPdfs);
147 initialize(pindices);
150 __host__ fptype AddPdf::normalize() const {
151 // if (cpuDebug & 1) std::cout << "Normalising AddPdf " << getName() << std::endl;
154 fptype totalWeight = 0;
156 for(unsigned int i = 0; i < components.size() - 1; ++i) {
157 fptype weight = host_params[host_indices[parameters + 3 * (i + 1)]];
158 totalWeight += weight;
159 fptype curr = components[i]->normalize();
160 ret += curr * weight;
163 fptype last = components.back()->normalize();
166 fptype lastWeight = host_params[host_indices[parameters + 3 * components.size()]];
167 totalWeight += lastWeight;
168 ret += last * lastWeight;
171 ret += (1 - totalWeight) * last;
174 host_normalisation[parameters] = 1.0;
176 if(getSpecialMask() & PdfBase::ForceCommonNorm) {
177 // Want to normalize this as
178 // (f1 A + (1-f1) B) / int (f1 A + (1-f1) B)
179 // instead of default
180 // (f1 A / int A) + ((1-f1) B / int B).
182 for(auto component : components) {
183 host_normalisation[component->getParameterIndex()] = (1.0 / ret);
187 // if (cpuDebug & 1) std::cout << getName() << " integral returning " << ret << std::endl;
191 __host__ double AddPdf::sumOfNll(int numVars) const {
192 static thrust::plus<double> cudaPlus;
193 thrust::constant_iterator<int> eventSize(numVars);
194 thrust::constant_iterator<fptype *> arrayAddress(dev_event_array);
197 thrust::counting_iterator<int> eventIndex(0);
201 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
202 goofit_policy my_policy;
203 double r = thrust::transform_reduce(
205 thrust::make_zip_iterator(thrust::make_tuple(eventIndex, arrayAddress, eventSize)),
206 thrust::make_zip_iterator(thrust::make_tuple(eventIndex + m_iEventsPerTask, arrayAddress, eventSize)),
211 double r = thrust::transform_reduce(
212 thrust::make_zip_iterator(thrust::make_tuple(eventIndex, arrayAddress, eventSize)),
213 thrust::make_zip_iterator(thrust::make_tuple(eventIndex + m_iEventsPerTask, arrayAddress, eventSize)),
219 MPI_Allreduce(&r, &ret, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
221 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
222 goofit_policy my_policy;
223 ret = thrust::transform_reduce(
225 thrust::make_zip_iterator(thrust::make_tuple(eventIndex, arrayAddress, eventSize)),
226 thrust::make_zip_iterator(thrust::make_tuple(eventIndex + numEntries, arrayAddress, eventSize)),
231 ret = thrust::transform_reduce(
232 thrust::make_zip_iterator(thrust::make_tuple(eventIndex, arrayAddress, eventSize)),
233 thrust::make_zip_iterator(thrust::make_tuple(eventIndex + numEntries, arrayAddress, eventSize)),
241 fptype expEvents = 0;
243 // std::cout << "Weights:";
244 for(unsigned int i = 0; i < components.size(); ++i) {
245 expEvents += host_params[host_indices[parameters + 3 * (i + 1)]];
246 // std::cout << " " << host_params[host_indices[parameters + 3*(i+1)]];
249 // Log-likelihood of numEvents with expectation of exp is (-exp + numEvents*ln(exp) - ln(numEvents!)).
250 // The last is constant, so we drop it; and then multiply by minus one to get the negative log-likelihood.
251 ret += (expEvents - numEvents * log(expEvents));
252 // std::cout << " " << expEvents << " " << numEvents << " " << (expEvents - numEvents*log(expEvents)) <<
258 } // namespace GooFit