Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ComputeFunctions.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Emmanouil Michalainas, CERN, Summer 2019
5 *
6 * Copyright (c) 2021, CERN
7 *
8 * Redistribution and use in source and binary forms,
9 * with or without modification, are permitted according to the terms
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
11 */
12
13/**
14\file ComputeFunctions.cxx
15
16This file contains vectorizable computation functions for PDFs and other Roofit objects.
17The same source file can also be compiled with nvcc. All functions have a single `Batches`
18object as an argument passed by value, which contains all the information necessary for the
19computation. In case of cuda computations, the loops have a step (stride) the size of the grid
20which allows for reusing the same code as the cpu implementations, easier debugging and in terms
21of performance, maximum memory coalescing. For more details, see
22https://developer.nvidia.com/blog/cuda-pro-tip-write-flexible-kernels-grid-stride-loops/
23**/
24
25#include "RooBatchCompute.h"
26#include "RooNaNPacker.h"
27#include "RooVDTHeaders.h"
28#include "Batches.h"
29
30#include <TMath.h>
31
33
34#include <vector>
35
36#ifdef __CUDACC__
37#define BEGIN blockDim.x *blockIdx.x + threadIdx.x
38#define STEP blockDim.x *gridDim.x
39#else
40#define BEGIN 0
41#define STEP 1
42#endif // #ifdef __CUDACC__
43
44namespace RooBatchCompute {
45namespace RF_ARCH {
46
48{
49 const int nPdfs = batches.nExtra;
50 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
51 batches.output[i] = batches.extra[0] * batches.args[0][i];
52 }
53 for (int pdf = 1; pdf < nPdfs; pdf++) {
54 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
55 batches.output[i] += batches.extra[pdf] * batches.args[pdf][i];
56 }
57 }
58}
59
61{
62 Batch m = batches.args[0];
63 Batch m0 = batches.args[1];
64 Batch c = batches.args[2];
65 Batch p = batches.args[3];
66 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
67 const double t = m[i] / m0[i];
68 const double u = 1 - t * t;
69 batches.output[i] = c[i] * u + p[i] * fast_log(u);
70 }
71 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
72 if (m[i] >= m0[i]) {
73 batches.output[i] = 0.0;
74 } else {
75 batches.output[i] = m[i] * fast_exp(batches.output[i]);
76 }
77 }
78}
79
81{
82 Batch coef0 = batches.args[0];
83 Batch coef1 = batches.args[1];
84 Batch tagFlav = batches.args[2];
85 Batch delMistag = batches.args[3];
86 Batch mixState = batches.args[4];
87 Batch mistag = batches.args[5];
88
89 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
90 batches.output[i] =
91 coef0[i] * (1.0 - tagFlav[i] * delMistag[0]) + coef1[i] * (mixState[i] * (1.0 - 2.0 * mistag[0]));
92 }
93}
94
96{
97 const int nCoef = batches.nExtra - 2;
98 const int degree = nCoef - 1;
99 const double xmin = batches.extra[nCoef];
100 const double xmax = batches.extra[nCoef + 1];
101 Batch xData = batches.args[0];
102
103 // The binomial coefficients are applied on the fly in the evaluation loops
104 // below. Note for the CUDA case: the coefficients must not be applied to
105 // batches.extra in-place, because the extra arguments live in global device
106 // memory that is shared by all threads.
107
108 if (STEP == 1) {
109 double X[bufferSize];
110 double _1_X[bufferSize];
111 double powX[bufferSize];
112 double pow_1_X[bufferSize];
113 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
114 powX[i] = pow_1_X[i] = 1.0;
115 X[i] = (xData[i] - xmin) / (xmax - xmin);
116 _1_X[i] = 1 - X[i];
117 batches.output[i] = 0.0;
118 }
119
120 // raising 1-x to the power of degree
121 for (int k = 2; k <= degree; k += 2) {
122 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
123 pow_1_X[i] *= _1_X[i] * _1_X[i];
124 }
125
126 if (degree % 2 == 1) {
127 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
128 pow_1_X[i] *= _1_X[i];
129 }
130
131 // inverting 1-x ---> 1/(1-x)
132 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
133 _1_X[i] = 1 / _1_X[i];
134
135 double binomial = 1.0;
136 for (int k = 0; k < nCoef; k++) {
137 const double coef = batches.extra[k] * binomial;
138 binomial = (binomial * (degree - k)) / (k + 1);
139 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
140 batches.output[i] += coef * powX[i] * pow_1_X[i];
141
142 // calculating next power for x and 1-x
143 powX[i] *= X[i];
144 pow_1_X[i] *= _1_X[i];
145 }
146 }
147 } else {
148 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
149 batches.output[i] = 0.0;
150 const double X = (xData[i] - xmin) / (xmax - xmin);
151 double powX = 1.0;
152 double pow_1_X = 1.0;
153 for (int k = 1; k <= degree; k++)
154 pow_1_X *= 1 - X;
155 const double _1_X = 1 / (1 - X);
156 double binomial = 1.0;
157 for (int k = 0; k < nCoef; k++) {
158 batches.output[i] += batches.extra[k] * binomial * powX * pow_1_X;
159 binomial = (binomial * (degree - k)) / (k + 1);
160 powX *= X;
161 pow_1_X *= _1_X;
162 }
163 }
164 }
165}
166
168{
169 Batch X = batches.args[0];
170 Batch M = batches.args[1];
171 Batch SL = batches.args[2];
172 Batch SR = batches.args[3];
173 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
174 double arg = X[i] - M[i];
175 if (arg < 0) {
176 arg /= SL[i];
177 } else {
178 arg /= SR[i];
179 }
180 batches.output[i] = fast_exp(-0.5 * arg * arg);
181 }
182}
183
185{
186 Batch X = batches.args[0];
187 Batch M = batches.args[1];
188 Batch W = batches.args[2];
189 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
190 const double arg = X[i] - M[i];
191 batches.output[i] = 1 / (arg * arg + 0.25 * W[i] * W[i]);
192 }
193}
194
196{
197 Batch X = batches.args[0];
198 Batch XP = batches.args[1];
199 Batch SP = batches.args[2];
200 Batch XI = batches.args[3];
201 Batch R1 = batches.args[4];
202 Batch R2 = batches.args[5];
203 const double r3 = log(2.0);
204 const double r6 = exp(-6.0);
205 const double r7 = 2 * sqrt(2 * log(2.0));
206
207 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
208 const double r1 = XI[i] * fast_isqrt(XI[i] * XI[i] + 1);
209 const double r4 = 1 / fast_isqrt(XI[i] * XI[i] + 1);
210 const double hp = 1 / (SP[i] * r7);
211 const double x1 = XP[i] + 0.5 * SP[i] * r7 * (r1 - 1);
212 const double x2 = XP[i] + 0.5 * SP[i] * r7 * (r1 + 1);
213
214 double r5 = 1.0;
215 if (XI[i] > r6 || XI[i] < -r6)
216 r5 = XI[i] / fast_log(r4 + XI[i]);
217
218 double factor = 1;
219 double y = X[i] - x1;
220 double Yp = XP[i] - x1;
221 double yi = r4 - XI[i];
222 double rho = R1[i];
223 if (X[i] >= x2) {
224 factor = -1;
225 y = X[i] - x2;
226 Yp = XP[i] - x2;
227 yi = r4 + XI[i];
228 rho = R2[i];
229 }
230
231 batches.output[i] = rho * y * y / Yp / Yp - r3 + factor * 4 * r3 * y * hp * r5 * r4 / yi / yi;
232 if (X[i] >= x1 && X[i] < x2) {
233 batches.output[i] =
234 fast_log(1 + 4 * XI[i] * r4 * (X[i] - XP[i]) * hp) / fast_log(1 + 2 * XI[i] * (XI[i] - r4));
235 batches.output[i] *= -batches.output[i] * r3;
236 }
237 if (X[i] >= x1 && X[i] < x2 && XI[i] < r6 && XI[i] > -r6)
238 batches.output[i] = -4 * r3 * (X[i] - XP[i]) * (X[i] - XP[i]) * hp * hp;
239 }
240 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
241 batches.output[i] = fast_exp(batches.output[i]);
242}
243
245{
246 Batch M = batches.args[0];
247 Batch M0 = batches.args[1];
248 Batch S = batches.args[2];
249 Batch A = batches.args[3];
250 Batch N = batches.args[4];
251 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
252 const double t = (M[i] - M0[i]) / S[i];
253 if ((A[i] > 0 && t >= -A[i]) || (A[i] < 0 && -t >= A[i])) {
254 batches.output[i] = -0.5 * t * t;
255 } else {
256 batches.output[i] = N[i] / (N[i] - A[i] * A[i] - A[i] * t);
257 batches.output[i] = fast_log(batches.output[i]);
258 batches.output[i] *= N[i];
259 batches.output[i] -= 0.5 * A[i] * A[i];
260 }
261 }
262 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
263 batches.output[i] = fast_exp(batches.output[i]);
264}
265
267{
268 Batch xData = batches.args[0];
269 const int nCoef = batches.nExtra - 2;
270 const double xmin = batches.extra[nCoef];
271 const double xmax = batches.extra[nCoef + 1];
272
273 if (STEP == 1) {
274 double prev[bufferSize][2];
275 double X[bufferSize];
276
277 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
278 // set a0-->prev[i][0] and a1-->prev[i][1]
279 // and x tranfsformed to range[-1..1]-->X[i]
280 prev[i][0] = batches.output[i] = 1.0;
281 prev[i][1] = X[i] = 2 * (xData[i] - 0.5 * (xmax + xmin)) / (xmax - xmin);
282 }
283 for (int k = 0; k < nCoef; k++) {
284 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
285 batches.output[i] += prev[i][1] * batches.extra[k];
286
287 // compute next order
288 const double next = 2 * X[i] * prev[i][1] - prev[i][0];
289 prev[i][0] = prev[i][1];
290 prev[i][1] = next;
291 }
292 }
293 } else {
294 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
295 double prev0 = 1.0;
296 double prev1 = 2 * (xData[i] - 0.5 * (xmax + xmin)) / (xmax - xmin);
297 double X = prev1;
298 batches.output[i] = 1.0;
299 for (int k = 0; k < nCoef; k++) {
300 batches.output[i] += prev1 * batches.extra[k];
301
302 // compute next order
303 const double next = 2 * X * prev1 - prev0;
304 prev0 = prev1;
305 prev1 = next;
306 }
307 }
308 }
309}
310
312{
313 Batch X = batches.args[0];
314 const double ndof = batches.extra[0];
315 const double gamma = 1 / std::tgamma(ndof / 2.0);
316 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
317 batches.output[i] = gamma;
318
319 constexpr double ln2 = 0.693147180559945309417232121458;
320 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
321 double arg = (ndof - 2) * fast_log(X[i]) - X[i] - ndof * ln2;
322 batches.output[i] *= fast_exp(0.5 * arg);
323 }
324}
325
327{
328 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
329 batches.output[i] = 0.0 + (batches.args[0][i] == 1.0);
330 }
331}
332
334{
335 Batch DM = batches.args[0];
336 Batch DM0 = batches.args[1];
337 Batch C = batches.args[2];
338 Batch A = batches.args[3];
339 Batch B = batches.args[4];
340 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
341 const double ratio = DM[i] / DM0[i];
342 const double arg1 = (DM0[i] - DM[i]) / C[i];
343 const double arg2 = A[i] * fast_log(ratio);
344 batches.output[i] = (1 - fast_exp(arg1)) * fast_exp(arg2) + B[i] * (ratio - 1);
345 }
346
347 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
348 if (batches.output[i] < 0)
349 batches.output[i] = 0;
350 }
351}
352
354{
355 int lowestOrder = batches.extra[0];
356 int nTerms = batches.extra[1];
357 auto x = batches.args[0];
358
359 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
360 batches.output[i] = 0.0;
361 double xTmp = std::pow(x[i], lowestOrder);
362 for (int k = 0; k < nTerms; ++k) {
363 batches.output[i] += batches.args[k + 1][i] * xTmp;
364 xTmp *= x[i];
365 }
366 batches.output[i] = std::exp(batches.output[i]);
367 }
368}
369
371{
372 Batch x = batches.args[0];
373 Batch c = batches.args[1];
374 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
375 batches.output[i] = fast_exp(x[i] * c[i]);
376 }
377}
378
380{
381 Batch x = batches.args[0];
382 Batch c = batches.args[1];
383 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
384 batches.output[i] = fast_exp(-x[i] * c[i]);
385 }
386}
387
389{
390 Batch X = batches.args[0];
391 Batch G = batches.args[1];
392 Batch B = batches.args[2];
393 Batch M = batches.args[3];
394 double gamma = -std::lgamma(G[0]);
395 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
396 if (X[i] == M[i]) {
397 batches.output[i] = int(G[i] == 1.0) / B[i];
398 } else if (G._isVector) {
399 batches.output[i] = -std::lgamma(G[i]);
400 } else {
401 batches.output[i] = gamma;
402 }
403 }
404
405 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
406 if (X[i] != M[i]) {
407 const double invBeta = 1 / B[i];
408 double arg = (X[i] - M[i]) * invBeta;
409 batches.output[i] -= arg;
410 arg = fast_log(arg);
411 batches.output[i] += arg * (G[i] - 1);
412 batches.output[i] = fast_exp(batches.output[i]);
413 batches.output[i] *= invBeta;
414 }
415 }
416}
417
419{
420 const double root2 = std::sqrt(2.);
421 const double root2pi = std::sqrt(2. * std::atan2(0., -1.));
422
423 const bool isMinus = batches.extra[0] < 0.0;
424 const bool isPlus = batches.extra[0] > 0.0;
425
426 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
427
428 const double x = batches.args[0][i];
429 const double mean = batches.args[1][i] * batches.args[2][i];
430 const double sigma = batches.args[3][i] * batches.args[4][i];
431 const double tau = batches.args[5][i];
432
433 if (tau == 0.0) {
434 // Straight Gaussian, used for unconvoluted PDF or expBasis with 0 lifetime
435 double xprime = (x - mean) / sigma;
436 double result = std::exp(-0.5 * xprime * xprime) / (sigma * root2pi);
437 if (!isMinus && !isPlus)
438 result *= 2;
439 batches.output[i] = result;
440 } else {
441 // Convolution with exp(-t/tau)
442 const double xprime = (x - mean) / tau;
443 const double c = sigma / (root2 * tau);
444 const double u = xprime / (2 * c);
445
446 double result = 0.0;
447 if (!isMinus)
449 if (!isPlus)
451 batches.output[i] = result;
452 }
453 }
454}
455
457{
458 auto x = batches.args[0];
459 auto mean = batches.args[1];
460 auto sigma = batches.args[2];
461 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
462 const double arg = x[i] - mean[i];
463 const double halfBySigmaSq = -0.5 / (sigma[i] * sigma[i]);
464 batches.output[i] = fast_exp(arg * arg * halfBySigmaSq);
465 }
466}
467
469{
470 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
471 batches.output[i] = batches.args[0][i];
472 }
473}
474
476{
477 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
478 batches.output[i] = -fast_log(batches.args[0][i]);
479 // Multiply by weights if they exist
480 if (batches.extra[0]) {
481 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
482 batches.output[i] *= batches.args[1][i];
483 }
484}
485
487{
488 Batch mass = batches.args[0];
489 Batch mu = batches.args[1];
490 Batch lambda = batches.args[2];
491 Batch gamma = batches.args[3];
492 Batch delta = batches.args[4];
493 const double sqrtTwoPi = std::sqrt(TMath::TwoPi());
494 const double massThreshold = batches.extra[0];
495
496 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
497 const double arg = (mass[i] - mu[i]) / lambda[i];
498#ifdef R__HAS_VDT
499 const double asinh_arg = fast_log(arg + 1 / fast_isqrt(arg * arg + 1));
500#else
501 const double asinh_arg = asinh(arg);
502#endif
503 const double expo = gamma[i] + delta[i] * asinh_arg;
504 const double result =
505 delta[i] * fast_exp(-0.5 * expo * expo) * fast_isqrt(1. + arg * arg) / (sqrtTwoPi * lambda[i]);
506
507 const double passThrough = mass[i] >= massThreshold;
508 batches.output[i] = result * passThrough;
509 }
510}
511
512/* Actual computation of Landau(x,mean,sigma) in a vectorization-friendly way
513 * Code copied from function landau_pdf (math/mathcore/src/PdfFuncMathCore.cxx)
514 * and rewritten to enable vectorization.
515 */
517{
518 auto case0 = [](double x) {
519 const double a1[3] = {0.04166666667, -0.01996527778, 0.02709538966};
520 const double u = fast_exp(x + 1.0);
521 return 0.3989422803 * fast_exp(-1 / u - 0.5 * (x + 1)) * (1 + (a1[0] + (a1[1] + a1[2] * u) * u) * u);
522 };
523 auto case1 = [](double x) {
524 constexpr double p1[5] = {0.4259894875, -0.1249762550, 0.03984243700, -0.006298287635, 0.001511162253};
525 constexpr double q1[5] = {1.0, -0.3388260629, 0.09594393323, -0.01608042283, 0.003778942063};
526 const double u = fast_exp(-x - 1);
527 return fast_exp(-u - 0.5 * (x + 1)) * (p1[0] + (p1[1] + (p1[2] + (p1[3] + p1[4] * x) * x) * x) * x) /
528 (q1[0] + (q1[1] + (q1[2] + (q1[3] + q1[4] * x) * x) * x) * x);
529 };
530 auto case2 = [](double x) {
531 constexpr double p2[5] = {0.1788541609, 0.1173957403, 0.01488850518, -0.001394989411, 0.0001283617211};
532 constexpr double q2[5] = {1.0, 0.7428795082, 0.3153932961, 0.06694219548, 0.008790609714};
533 return (p2[0] + (p2[1] + (p2[2] + (p2[3] + p2[4] * x) * x) * x) * x) /
534 (q2[0] + (q2[1] + (q2[2] + (q2[3] + q2[4] * x) * x) * x) * x);
535 };
536 auto case3 = [](double x) {
537 constexpr double p3[5] = {0.1788544503, 0.09359161662, 0.006325387654, 0.00006611667319, -0.000002031049101};
538 constexpr double q3[5] = {1.0, 0.6097809921, 0.2560616665, 0.04746722384, 0.006957301675};
539 return (p3[0] + (p3[1] + (p3[2] + (p3[3] + p3[4] * x) * x) * x) * x) /
540 (q3[0] + (q3[1] + (q3[2] + (q3[3] + q3[4] * x) * x) * x) * x);
541 };
542 auto case4 = [](double x) {
543 constexpr double p4[5] = {0.9874054407, 118.6723273, 849.2794360, -743.7792444, 427.0262186};
544 constexpr double q4[5] = {1.0, 106.8615961, 337.6496214, 2016.712389, 1597.063511};
545 const double u = 1 / x;
546 return u * u * (p4[0] + (p4[1] + (p4[2] + (p4[3] + p4[4] * u) * u) * u) * u) /
547 (q4[0] + (q4[1] + (q4[2] + (q4[3] + q4[4] * u) * u) * u) * u);
548 };
549 auto case5 = [](double x) {
550 constexpr double p5[5] = {1.003675074, 167.5702434, 4789.711289, 21217.86767, -22324.94910};
551 constexpr double q5[5] = {1.0, 156.9424537, 3745.310488, 9834.698876, 66924.28357};
552 const double u = 1 / x;
553 return u * u * (p5[0] + (p5[1] + (p5[2] + (p5[3] + p5[4] * u) * u) * u) * u) /
554 (q5[0] + (q5[1] + (q5[2] + (q5[3] + q5[4] * u) * u) * u) * u);
555 };
556 auto case6 = [](double x) {
557 constexpr double p6[5] = {1.000827619, 664.9143136, 62972.92665, 475554.6998, -5743609.109};
558 constexpr double q6[5] = {1.0, 651.4101098, 56974.73333, 165917.4725, -2815759.939};
559 const double u = 1 / x;
560 return u * u * (p6[0] + (p6[1] + (p6[2] + (p6[3] + p6[4] * u) * u) * u) * u) /
561 (q6[0] + (q6[1] + (q6[2] + (q6[3] + q6[4] * u) * u) * u) * u);
562 };
563 auto case7 = [](double x) {
564 const double a2[2] = {-1.845568670, -4.284640743};
565 const double u = 1 / (x - x * fast_log(x) / (x + 1));
566 return u * u * (1 + (a2[0] + a2[1] * u) * u);
567 };
568
569 Batch X = batches.args[0];
570 Batch M = batches.args[1];
571 Batch S = batches.args[2];
572
573 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
574 batches.output[i] = (X[i] - M[i]) / S[i];
575
576 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
577 if (S[i] <= 0.0) {
578 batches.output[i] = 0;
579 } else if (batches.output[i] < -5.5) {
580 batches.output[i] = case0(batches.output[i]);
581 } else if (batches.output[i] < -1.0) {
582 batches.output[i] = case1(batches.output[i]);
583 } else if (batches.output[i] < 1.0) {
584 batches.output[i] = case2(batches.output[i]);
585 } else if (batches.output[i] < 5.0) {
586 batches.output[i] = case3(batches.output[i]);
587 } else if (batches.output[i] < 12.0) {
588 batches.output[i] = case4(batches.output[i]);
589 } else if (batches.output[i] < 50.0) {
590 batches.output[i] = case5(batches.output[i]);
591 } else if (batches.output[i] < 300.) {
592 batches.output[i] = case6(batches.output[i]);
593 } else {
594 batches.output[i] = case7(batches.output[i]);
595 }
596 }
597}
598
600{
601 Batch X = batches.args[0];
602 Batch M0 = batches.args[1];
603 Batch K = batches.args[2];
604 constexpr double rootOf2pi = 2.506628274631000502415765284811;
605 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
606 double lnxOverM0 = fast_log(X[i] / M0[i]);
607 double lnk = fast_log(K[i]);
608 if (lnk < 0)
609 lnk = -lnk;
610 double arg = lnxOverM0 / lnk;
611 arg *= -0.5 * arg;
612 batches.output[i] = fast_exp(arg) / (X[i] * lnk * rootOf2pi);
613 }
614}
615
617{
618 Batch X = batches.args[0];
619 Batch M0 = batches.args[1];
620 Batch K = batches.args[2];
621 constexpr double rootOf2pi = 2.506628274631000502415765284811;
622 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
623 double lnxOverM0 = fast_log(X[i]) - M0[i];
624 double lnk = K[i];
625 if (lnk < 0)
626 lnk = -lnk;
627 double arg = lnxOverM0 / lnk;
628 arg *= -0.5 * arg;
629 batches.output[i] = fast_exp(arg) / (X[i] * lnk * rootOf2pi);
630 }
631}
632
634{
635 auto rawVal = batches.args[0];
636 auto normVal = batches.args[1];
637
638 int nEvalErrorsType0 = 0;
639 int nEvalErrorsType1 = 0;
640 int nEvalErrorsType2 = 0;
641
642 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
643 double out = 0.0;
644 // batches.output[i] = rawVal[i] / normVar[i];
645 if (normVal[i] < 0. || (normVal[i] == 0. && rawVal[i] != 0)) {
646 // Unreasonable normalisations. A zero integral can be tolerated if the function vanishes, though.
647 out = RooNaNPacker::packFloatIntoNaN(-normVal[i] + (rawVal[i] < 0. ? -rawVal[i] : 0.));
649 } else if (rawVal[i] < 0.) {
650 // The pdf value is less than zero.
653 } else if (std::isnan(rawVal[i])) {
654 // The pdf value is Not-a-Number.
655 out = rawVal[i];
657 } else {
658 out = (rawVal[i] == 0. && normVal[i] == 0.) ? 0. : rawVal[i] / normVal[i];
659 }
660 batches.output[i] = out;
661 }
662
663 // The counters live in memory that is shared between all threads in the
664 // CUDA case, so they need to be accumulated atomically there. Note that
665 // the CPU branch below is only safe because the CPU implementation runs
666 // single-threaded: with implicit multi-threading, the workers would share
667 // this memory as well and would also need atomic accumulation.
668#ifdef __CUDACC__
669 if (nEvalErrorsType0 > 0)
670 atomicAdd(&batches.extra[0], double(nEvalErrorsType0));
671 if (nEvalErrorsType1 > 0)
672 atomicAdd(&batches.extra[1], double(nEvalErrorsType1));
673 if (nEvalErrorsType2 > 0)
674 atomicAdd(&batches.extra[2], double(nEvalErrorsType2));
675#else
676 batches.extra[0] = batches.extra[0] + nEvalErrorsType0;
677 batches.extra[1] = batches.extra[1] + nEvalErrorsType1;
678 batches.extra[2] = batches.extra[2] + nEvalErrorsType2;
679#endif
680}
681
682/* TMath::ASinH(x) needs to be replaced with ln( x + sqrt(x^2+1))
683 * argasinh -> the argument of TMath::ASinH()
684 * argln -> the argument of the logarithm that replaces AsinH
685 * asinh -> the value that the function evaluates to
686 *
687 * ln is the logarithm that was solely present in the initial
688 * formula, that is before the asinh replacement
689 */
691{
692 Batch X = batches.args[0];
693 Batch P = batches.args[1];
694 Batch W = batches.args[2];
695 Batch T = batches.args[3];
696 constexpr double xi = 2.3548200450309494; // 2 Sqrt( Ln(4) )
697 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
698 double argasinh = 0.5 * xi * T[i];
699 double argln = argasinh + 1 / fast_isqrt(argasinh * argasinh + 1);
700 double asinh = fast_log(argln);
701
702 double argln2 = 1 - (X[i] - P[i]) * T[i] / W[i];
703 double ln = fast_log(argln2);
704 batches.output[i] = ln / asinh;
705 batches.output[i] *= -0.125 * xi * xi * batches.output[i];
706 batches.output[i] -= 2.0 / xi / xi * asinh * asinh;
707 }
708
709 // faster if you exponentiate in a separate loop (dark magic!)
710 for (size_t i = BEGIN; i < batches.nEvents; i += STEP)
711 batches.output[i] = fast_exp(batches.output[i]);
712}
713
715{
716 Batch x = batches.args[0];
717 Batch mean = batches.args[1];
718 bool protectNegative = batches.extra[0];
719 bool noRounding = batches.extra[1];
720 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
721 const double x_i = noRounding ? x[i] : floor(x[i]);
722 batches.output[i] = std::lgamma(x_i + 1.);
723 }
724
725 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
726 const double x_i = noRounding ? x[i] : floor(x[i]);
727 const double logMean = fast_log(mean[i]);
728 const double logPoisson = x_i * logMean - mean[i] - batches.output[i];
729 batches.output[i] = fast_exp(logPoisson);
730
731 // Cosmetics
732 if (x_i < 0) {
733 batches.output[i] = 0;
734 } else if (x_i == 0) {
735 batches.output[i] = 1 / fast_exp(mean[i]);
736 }
737
738 if (protectNegative && mean[i] < 0)
739 batches.output[i] = 1.E-3;
740 }
741}
742
744{
745 const int nCoef = batches.extra[0];
746 const std::size_t nEvents = batches.nEvents;
747 Batch x = batches.args[nCoef];
748
749 for (size_t i = BEGIN; i < nEvents; i += STEP) {
750 batches.output[i] = batches.args[nCoef - 1][i];
751 }
752
753 // Indexes are in range 0..nCoef-1 but coefList[nCoef-1] has already been
754 // processed.
755 for (int k = nCoef - 2; k >= 0; k--) {
756 for (size_t i = BEGIN; i < nEvents; i += STEP) {
757 batches.output[i] = batches.args[k][i] + x[i] * batches.output[i];
758 }
759 }
760}
761
763{
764 const int nCoef = batches.extra[0];
765 Batch x = batches.args[0];
766
767 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
768 batches.output[i] = 0.0;
769 for (int k = 0; k < nCoef; ++k) {
770 batches.output[i] += batches.args[2 * k + 1][i] * std::pow(x[i], batches.args[2 * k + 2][i]);
771 }
772 }
773}
774
776{
777 const int nPdfs = batches.extra[0];
778 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
779 batches.output[i] = 1.;
780 }
781 for (int pdf = 0; pdf < nPdfs; pdf++) {
782 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
783 batches.output[i] *= batches.args[pdf][i];
784 }
785 }
786}
787
789{
790 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
791 batches.output[i] = batches.args[0][i] / batches.args[1][i];
792 }
793}
794
796{
797
798 const bool isMinus = batches.extra[0] < 0.0;
799 const bool isPlus = batches.extra[0] > 0.0;
800 for (std::size_t i = BEGIN; i < batches.nEvents; i += STEP) {
801 double x = batches.args[0][i];
802 // Enforce sign compatibility
803 const bool isOutOfSign = (isMinus && x > 0.0) || (isPlus && x < 0.0);
804 batches.output[i] = isOutOfSign ? 0.0 : fast_exp(-std::abs(x) / batches.args[1][i]);
805 }
806}
807
809{
810 const bool isMinus = batches.extra[0] < 0.0;
811 const bool isPlus = batches.extra[0] > 0.0;
812 for (std::size_t i = BEGIN; i < batches.nEvents; i += STEP) {
813 double x = batches.args[0][i];
814 // Enforce sign compatibility
815 const bool isOutOfSign = (isMinus && x > 0.0) || (isPlus && x < 0.0);
816 batches.output[i] =
817 isOutOfSign ? 0.0 : fast_exp(-std::abs(x) / batches.args[1][i]) * fast_sin(x * batches.args[2][i]);
818 }
819}
820
822{
823 const bool isMinus = batches.extra[0] < 0.0;
824 const bool isPlus = batches.extra[0] > 0.0;
825 for (std::size_t i = BEGIN; i < batches.nEvents; i += STEP) {
826 double x = batches.args[0][i];
827 // Enforce sign compatibility
828 const bool isOutOfSign = (isMinus && x > 0.0) || (isPlus && x < 0.0);
829 batches.output[i] =
830 isOutOfSign ? 0.0 : fast_exp(-std::abs(x) / batches.args[1][i]) * fast_cos(x * batches.args[2][i]);
831 }
832}
833
835{
836 const bool isMinus = batches.extra[0] < 0.0;
837 const bool isPlus = batches.extra[0] > 0.0;
838 for (std::size_t i = BEGIN; i < batches.nEvents; i += STEP) {
839 double x = batches.args[0][i];
840 // Enforce sign compatibility
841 const bool isOutOfSign = (isMinus && x > 0.0) || (isPlus && x < 0.0);
842 if (isOutOfSign) {
843 batches.output[i] = 0.0;
844 } else {
845 const double tscaled = std::abs(x) / batches.args[1][i];
846 batches.output[i] = fast_exp(-tscaled) * tscaled;
847 }
848 }
849}
850
852{
853 const bool isMinus = batches.extra[0] < 0.0;
854 const bool isPlus = batches.extra[0] > 0.0;
855 for (std::size_t i = BEGIN; i < batches.nEvents; i += STEP) {
856 double x = batches.args[0][i];
857 // Enforce sign compatibility
858 const bool isOutOfSign = (isMinus && x > 0.0) || (isPlus && x < 0.0);
859 if (isOutOfSign) {
860 batches.output[i] = 0.0;
861 } else {
862 const double tscaled = std::abs(x) / batches.args[1][i];
863 batches.output[i] = fast_exp(-tscaled) * tscaled * tscaled;
864 }
865 }
866}
867
869{
870 const bool isMinus = batches.extra[0] < 0.0;
871 const bool isPlus = batches.extra[0] > 0.0;
872 for (std::size_t i = BEGIN; i < batches.nEvents; i += STEP) {
873 double x = batches.args[0][i];
874 // Enforce sign compatibility
875 const bool isOutOfSign = (isMinus && x > 0.0) || (isPlus && x < 0.0);
876 batches.output[i] =
877 isOutOfSign ? 0.0 : fast_exp(-std::abs(x) / batches.args[1][i]) * sinh(x * batches.args[2][i] * 0.5);
878 }
879}
880
882{
883 const bool isMinus = batches.extra[0] < 0.0;
884 const bool isPlus = batches.extra[0] > 0.0;
885 for (std::size_t i = BEGIN; i < batches.nEvents; i += STEP) {
886 double x = batches.args[0][i];
887 // Enforce sign compatibility
888 const bool isOutOfSign = (isMinus && x > 0.0) || (isPlus && x < 0.0);
889 batches.output[i] =
890 isOutOfSign ? 0.0 : fast_exp(-std::abs(x) / batches.args[1][i]) * cosh(x * batches.args[2][i] * .5);
891 }
892}
893
895{
896 Batch X = batches.args[0];
897 Batch M = batches.args[1];
898 Batch W = batches.args[2];
899 Batch S = batches.args[3];
900 const double invSqrt2 = 0.707106781186547524400844362105;
901 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
902 const double arg = (X[i] - M[i]) * (X[i] - M[i]);
903 if (S[i] == 0.0 && W[i] == 0.0) {
904 batches.output[i] = 1.0;
905 } else if (S[i] == 0.0) {
906 batches.output[i] = 1 / (arg + 0.25 * W[i] * W[i]);
907 } else if (W[i] == 0.0) {
908 batches.output[i] = fast_exp(-0.5 * arg / (S[i] * S[i]));
909 } else {
910 batches.output[i] = invSqrt2 / S[i];
911 }
912 }
913
914 for (size_t i = BEGIN; i < batches.nEvents; i += STEP) {
915 if (S[i] != 0.0 && W[i] != 0.0) {
916 if (batches.output[i] < 0)
917 batches.output[i] = -batches.output[i];
918 const double factor = W[i] > 0.0 ? 0.5 : -0.5;
919 RooHeterogeneousMath::STD::complex<double> z(batches.output[i] * (X[i] - M[i]),
920 factor * batches.output[i] * W[i]);
921 batches.output[i] *= RooHeterogeneousMath::faddeeva(z).real();
922 }
923 }
924}
925
926/// Returns a std::vector of pointers to the compute functions in this file.
969} // End namespace RF_ARCH
970} // End namespace RooBatchCompute
#define __rooglobal__
Definition AccHeaders.h:37
#define RF_ARCH
#define STEP
#define BEGIN
#define c(i)
Definition RSha256.hxx:101
#define X(type, name)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
float xmin
float xmax
const Double_t sigma
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
__rooglobal__ void computeBreitWigner(Batches &batches)
__rooglobal__ void computeNovosibirsk(Batches &batches)
__rooglobal__ void computeExpPoly(Batches &batches)
__rooglobal__ void computeChiSquare(Batches &batches)
__rooglobal__ void computeDeltaFunction(Batches &batches)
__rooglobal__ void computeGamma(Batches &batches)
__rooglobal__ void computeTruthModelQuadBasis(Batches &batches)
__rooglobal__ void computeTruthModelExpBasis(Batches &batches)
__rooglobal__ void computeTruthModelLinBasis(Batches &batches)
__rooglobal__ void computeLognormalStandard(Batches &batches)
__rooglobal__ void computeTruthModelCoshBasis(Batches &batches)
__rooglobal__ void computeAddPdf(Batches &batches)
__rooglobal__ void computeBifurGauss(Batches &batches)
__rooglobal__ void computeTruthModelSinhBasis(Batches &batches)
__rooglobal__ void computeLognormal(Batches &batches)
__rooglobal__ void computeArgusBG(Batches &batches)
__rooglobal__ void computeGaussian(Batches &batches)
__rooglobal__ void computeLandau(Batches &batches)
__rooglobal__ void computeTruthModelSinBasis(Batches &batches)
__rooglobal__ void computePower(Batches &batches)
__rooglobal__ void computeExponentialNeg(Batches &batches)
__rooglobal__ void computePoisson(Batches &batches)
__rooglobal__ void computeJohnson(Batches &batches)
__rooglobal__ void computeBMixDecay(Batches &batches)
__rooglobal__ void computeChebychev(Batches &batches)
__rooglobal__ void computeNormalizedPdf(Batches &batches)
__rooglobal__ void computeBernstein(Batches &batches)
__rooglobal__ void computeRatio(Batches &batches)
__rooglobal__ void computePolynomial(Batches &batches)
__rooglobal__ void computeExponential(Batches &batches)
__rooglobal__ void computeTruthModelCosBasis(Batches &batches)
__rooglobal__ void computeGaussModelExpBasis(Batches &batches)
__rooglobal__ void computeBukin(Batches &batches)
__rooglobal__ void computeDstD0BG(Batches &batches)
__rooglobal__ void computeNegativeLogarithms(Batches &batches)
__rooglobal__ void computeIdentity(Batches &batches)
__rooglobal__ void computeCBShape(Batches &batches)
__rooglobal__ void computeProdPdf(Batches &batches)
__rooglobal__ void computeVoigtian(Batches &batches)
std::vector< void(*)(Batches &)> getFunctions()
Namespace for dispatching RooFit computations to various backends.
__roodevice__ double fast_exp(double x)
__roodevice__ double fast_sin(double x)
constexpr std::size_t bufferSize
__roodevice__ double fast_log(double x)
__roodevice__ double fast_cos(double x)
__roodevice__ double fast_isqrt(double x)
STD::complex< double > faddeeva(STD::complex< double > z)
STD::complex< double > evalCerf(double swt, double u, double c)
constexpr Double_t TwoPi()
Definition TMath.h:47
static double packFloatIntoNaN(float payload)
Pack float into mantissa of a NaN.
TMarker m
Definition textangle.C:8