124 _x(
"x",
"x", this,
x),
125 _lambda(
"lambda",
"Lambda", this, lambda),
126 _zeta(
"zeta",
"zeta", this, zeta),
127 _beta(
"beta",
"Asymmetry parameter beta", this, beta),
128 _sigma(
"sigma",
"Width parameter sigma", this, argSigma),
129 _mu(
"mu",
"Location parameter mu", this, mu),
130 _a(
"a",
"Left tail location a", this,
a),
131 _n(
"n",
"Left tail parameter n", this,
n),
132 _a2(
"a2",
"Right tail location a2", this, a2),
133 _n2(
"n2",
"Right tail parameter n2", this, n2)
139 std::string(
"Lambda needs to be negative when ") +
_zeta.
GetName() +
" is zero.");
150 _x(
"x", this, other._x),
151 _lambda(
"lambda", this, other._lambda),
152 _zeta(
"zeta", this, other._zeta),
153 _beta(
"beta", this, other._beta),
154 _sigma(
"sigma", this, other._sigma),
155 _mu(
"mu", this, other._mu),
156 _a(
"a", this, other._a),
157 _n(
"n", this, other._n),
158 _a2(
"a2", this, other._a2),
159 _n2(
"n2", this, other._n2)
165const double logsq2pi = std::log(std::sqrt(
TMath::TwoPi()));
166const double ln2 = std::log(2.);
168double low_x_BK(
double nu,
double x){
169 return TMath::Gamma(nu)*std::pow(2., nu-1.)*std::pow(
x, -nu);
172double low_x_LnBK(
double nu,
double x){
173 return std::log(
TMath::Gamma(nu)) + ln2*(nu-1.) - std::log(
x) * nu;
176double besselK(
double ni,
double x) {
177 const double nu = std::abs(ni);
178 if ((x < 1.e-06 && nu > 0.) ||
179 (x < 1.e-04 && nu > 0. && nu < 55.) ||
180 (x < 0.1 && nu >= 55.) )
181 return low_x_BK(nu,
x);
186double LnBesselK(
double ni,
double x) {
187 const double nu = std::abs(ni);
188 if ((x < 1.e-06 && nu > 0.) ||
189 (x < 1.e-04 && nu > 0. && nu < 55.) ||
190 (x < 0.1 && nu >= 55.) )
191 return low_x_LnBK(nu,
x);
197double LogEval(
double d,
double l,
double alpha,
double beta,
double delta) {
198 const double gamma = alpha;
199 const double dg = delta*
gamma;
200 const double thing = delta*delta +
d*
d;
201 const double logno =
l*std::log(gamma/delta) - logsq2pi - LnBesselK(
l, dg);
203 return std::exp(logno + beta*
d
204 + (0.5-
l)*(std::log(alpha)-0.5*std::log(thing))
205 + LnBesselK(
l-0.5, alpha*std::sqrt(thing)) );
210double diff_eval(
double d,
double l,
double alpha,
double beta,
double delta){
211 const double gamma = alpha;
212 const double dg = delta*
gamma;
214 const double thing = delta*delta +
d*
d;
215 const double sqrthing = std::sqrt(thing);
216 const double alphasq = alpha*sqrthing;
217 const double no = std::pow(gamma/delta,
l)/besselK(
l, dg)*sq2pi_inv;
218 const double ns1 = 0.5-
l;
220 return no * std::pow(alpha, ns1) * std::pow(thing,
l/2. - 1.25)
221 * ( -
d * alphasq * (besselK(
l - 1.5, alphasq)
222 + besselK(
l + 0.5, alphasq))
223 + (2.*(beta*thing +
d*
l) -
d) * besselK(ns1, alphasq) )
224 * std::exp(beta*
d) * 0.5;
245 const double cons0 = std::sqrt(
_zeta);
248 const double beta =
_beta;
255 const double cons1 =
_sigma/std::sqrt(phi);
256 const double alpha = cons0/cons1;
257 const double delta = cons0*cons1;
260 const double k1 = LogEval(-asigma,
_lambda, alpha, beta, delta);
261 const double k2 = diff_eval(-asigma,
_lambda, alpha, beta, delta);
262 const double B = -asigma +
_n*k1/k2;
263 const double A = k1 * std::pow(B+asigma,
_n);
265 out = A * std::pow(B-
d, -
_n);
267 else if (
d>a2sigma) {
268 const double k1 = LogEval(a2sigma,
_lambda, alpha, beta, delta);
269 const double k2 = diff_eval(a2sigma,
_lambda, alpha, beta, delta);
270 const double B = -a2sigma -
_n2*k1/k2;
271 const double A = k1 * std::pow(B+a2sigma,
_n2);
273 out = A * std::pow(B+
d, -
_n2);
276 out = LogEval(
d,
_lambda, alpha, beta, delta);
279 else if (
_zeta < 0.) {
280 coutE(Eval) <<
"The parameter " <<
_zeta.
GetName() <<
" of the RooHypatia2 " <<
GetName() <<
" cannot be < 0." << std::endl;
283 const double delta =
_sigma;
286 const double cons1 = std::exp(-beta*asigma);
287 const double phi = 1. +
_a *
_a;
288 const double k1 = cons1 * std::pow(phi,
_lambda-0.5);
289 const double k2 = beta*k1 - cons1*(
_lambda-0.5) * std::pow(phi,
_lambda-1.5) * 2.*
_a/delta;
290 const double B = -asigma +
_n*k1/k2;
291 const double A = k1*std::pow(B+asigma,
_n);
293 out = A*std::pow(B-
d, -
_n);
295 else if (
d > a2sigma) {
296 const double cons1 = std::exp(beta*a2sigma);
297 const double phi = 1. +
_a2*
_a2;
298 const double k1 = cons1 * std::pow(phi,
_lambda-0.5);
299 const double k2 = beta*k1 + cons1*(
_lambda-0.5) * std::pow(phi,
_lambda-1.5) * 2.*
_a2/delta;
300 const double B = -a2sigma -
_n2*k1/k2;
301 const double A = k1*std::pow(B+a2sigma,
_n2);
303 out = A*std::pow(B+
d, -
_n2);
306 out = std::exp(beta*
d) * std::pow(1. +
d*
d/(delta*delta),
_lambda - 0.5);
310 coutE(Eval) <<
"zeta = 0 only supported for lambda < 0. lambda = " <<
double(
_lambda) << std::endl;
320template<
typename Tx,
typename Tl,
typename Tz,
typename Tb,
typename Ts,
typename Tm,
typename Ta,
typename Tn,
321typename Ta2,
typename Tn2>
322void compute(std::span<double>
output, Tx
x, Tl lambda, Tz zeta, Tb beta, Ts
sigma, Tm mu, Ta
a, Tn
n, Ta2 a2, Tn2 n2) {
324 const bool zetaIsAlwaysLargerZero = !zeta.isBatch() && zeta[0] > 0.;
325 const bool zetaIsAlwaysZero = !zeta.isBatch() && zeta[0] == 0.;
327 for (std::size_t i = 0; i <
N; ++i) {
329 const double d =
x[i] - mu[i];
330 const double cons0 = std::sqrt(zeta[i]);
331 const double asigma =
a[i]*
sigma[i];
332 const double a2sigma = a2[i]*
sigma[i];
335 if (zetaIsAlwaysLargerZero || zeta[i] > 0.) {
336 const double phi = besselK(lambda[i]+1., zeta[i]) / besselK(lambda[i], zeta[i]);
337 const double cons1 =
sigma[i]/std::sqrt(phi);
338 const double alpha = cons0/cons1;
339 const double delta = cons0*cons1;
342 const double k1 = LogEval(-asigma, lambda[i], alpha, beta[i], delta);
343 const double k2 = diff_eval(-asigma, lambda[i], alpha, beta[i], delta);
344 const double B = -asigma +
n[i]*k1/k2;
345 const double A = k1 * std::pow(B+asigma,
n[i]);
347 output[i] = A * std::pow(B-
d, -
n[i]);
349 else if (
d>a2sigma) {
350 const double k1 = LogEval(a2sigma, lambda[i], alpha, beta[i], delta);
351 const double k2 = diff_eval(a2sigma, lambda[i], alpha, beta[i], delta);
352 const double B = -a2sigma - n2[i]*k1/k2;
353 const double A = k1 * std::pow(B+a2sigma, n2[i]);
355 output[i] = A * std::pow(B+
d, -n2[i]);
358 output[i] = LogEval(
d, lambda[i], alpha, beta[i], delta);
362 if ((!zetaIsAlwaysLargerZero && zetaIsAlwaysZero) || (zeta[i] == 0. && lambda[i] < 0.)) {
363 const double delta =
sigma[i];
366 const double cons1 = std::exp(-beta[i]*asigma);
367 const double phi = 1. +
a[i] *
a[i];
368 const double k1 = cons1 * std::pow(phi, lambda[i]-0.5);
369 const double k2 =
beta[i]*k1 - cons1*(lambda[i]-0.5) * std::pow(phi, lambda[i]-1.5) * 2.*
a[i]/delta;
370 const double B = -asigma +
n[i]*k1/k2;
371 const double A = k1*std::pow(B+asigma,
n[i]);
375 else if (
d > a2sigma) {
376 const double cons1 = std::exp(beta[i]*a2sigma);
377 const double phi = 1. + a2[i]*a2[i];
378 const double k1 = cons1 * std::pow(phi, lambda[i]-0.5);
379 const double k2 =
beta[i]*k1 + cons1*(lambda[i]-0.5) * std::pow(phi, lambda[i]-1.5) * 2.*a2[i]/delta;
380 const double B = -a2sigma - n2[i]*k1/k2;
381 const double A = k1*std::pow(B+a2sigma, n2[i]);
383 output[i] = A*std::pow(B+
d, -n2[i]);
386 output[i] = std::exp(beta[i]*
d) * std::pow(1. +
d*
d/(delta*delta), lambda[i] - 0.5);
393std::pair<double, double> computeAB_zetaNZero(
double asigma,
double lambda,
double alpha,
double beta,
double delta,
double n) {
394 const double k1 = LogEval(right ? asigma : -asigma, lambda, alpha,
beta, delta);
395 const double k2 = diff_eval(right ? asigma : -asigma, lambda, alpha,
beta, delta);
396 const double B = -asigma + (right ? -1 : 1.) *
n*k1/k2;
397 const double A = k1 * std::pow(B+asigma,
n);
403std::pair<double, double> computeAB_zetaZero(
double beta,
double asigma,
double a,
double lambda,
double delta,
double n) {
404 const double cons1 = std::exp((right ? 1. : -1.) *
beta*asigma);
405 const double phi = 1. +
a *
a;
406 const double k1 = cons1 * std::pow(phi, lambda-0.5);
407 const double k2 =
beta*k1 + (right ? 1. : -1) * cons1*(lambda-0.5) * std::pow(phi, lambda-1.5) * 2.*
a/delta;
408 const double B = -asigma + (right ? -1. : 1.) *
n*k1/k2;
409 const double A = k1*std::pow(B+asigma,
n);
419 BracketAdapter<double> lambda, BracketAdapter<double> zeta, BracketAdapter<double> beta,
420 BracketAdapter<double>
sigma, BracketAdapter<double> mu,
421 BracketAdapter<double>
a, BracketAdapter<double>
n, BracketAdapter<double> a2, BracketAdapter<double> n2) {
424 const double cons0 = std::sqrt(zeta);
425 const double asigma =
a*
sigma;
426 const double a2sigma = a2*
sigma;
429 const double phi = besselK(lambda+1., zeta) / besselK(lambda, zeta);
430 const double cons1 =
sigma/std::sqrt(phi);
431 const double alpha = cons0/cons1;
432 const double delta = cons0*cons1;
434 const auto AB_l = computeAB_zetaNZero<false>(asigma, lambda, alpha, beta, delta,
n);
435 const auto AB_r = computeAB_zetaNZero<true>(a2sigma, lambda, alpha, beta, delta, n2);
437 for (std::size_t i = 0; i <
N; ++i) {
438 const double d =
x[i] - mu[i];
441 output[i] = AB_l.first * std::pow(AB_l.second -
d, -
n);
443 else if (
d>a2sigma) {
444 output[i] = AB_r.first * std::pow(AB_r.second +
d, -n2);
447 output[i] = LogEval(
d, lambda, alpha, beta, delta);
450 }
else if (zeta == 0. && lambda < 0.) {
451 const double delta =
sigma;
453 const auto AB_l = computeAB_zetaZero<false>(beta, asigma,
a, lambda, delta,
n);
454 const auto AB_r = computeAB_zetaZero<true>(beta, a2sigma, a2, lambda, delta, n2);
456 for (std::size_t i = 0; i <
N; ++i) {
457 const double d =
x[i] - mu[i];
460 output[i] = AB_l.first*std::pow(AB_l.second -
d, -
n);
462 else if (
d > a2sigma) {
463 output[i] = AB_r.first * std::pow(AB_r.second +
d, -n2);
466 output[i] = std::exp(beta*
d) * std::pow(1. +
d*
d/(delta*delta), lambda - 0.5);
483 auto mu = ctx.
at(
_mu);
486 auto a2 = ctx.
at(
_a2);
487 auto n2 = ctx.
at(
_n2);
489 size_t paramSizeSum=0;
490 for (
const auto& i:{lambda, zeta, beta, sig, mu,
a,
n, a2, n2}) {
491 paramSizeSum += i.size();
495 if (
x.size()>1 && paramSizeSum==9) {
bool isConstant() const
Check if the "Constant" attribute is set.
Abstract interface for all probability density functions.
Abstract base class for objects that represent a real value and implements functionality common to al...
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Little adapter that gives a bracket operator to types that don't have one.
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
std::span< double > output()
RooHypatia2 is the two-sided version of the Hypatia distribution described in https://arxiv....
void doEval(RooFit::EvalContext &) const override
Base function for computing multiple values of a RooAbsReal.
double evaluate() const override
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
const char * GetName() const override
Returns name of object.
double beta(double x, double y)
Calculates the beta function.
double cyl_bessel_k(double nu, double x)
Calculates the modified Bessel functions of the second kind (also called irregular modified (cylindri...
Namespace for dispatching RooFit computations to various backends.
void compute(Config cfg, Computer comp, std::span< double > output, VarSpan vars, ArgSpan extraArgs={})
void checkRangeOfParameters(const RooAbsReal *callingClass, std::initializer_list< const RooAbsReal * > pars, double min=-std::numeric_limits< double >::max(), double max=std::numeric_limits< double >::max(), bool limitsInAllowedRange=false, std::string const &extraMessage="")
Check if the parameters have a range, and warn if the range extends below / above the set limits.
Double_t Gamma(Double_t z)
Computation of gamma(z) for all z.
constexpr Double_t TwoPi()