126 _x(
"x",
"x", this,
x),
127 _lambda(
"lambda",
"Lambda", this, lambda),
128 _zeta(
"zeta",
"zeta", this, zeta),
129 _beta(
"beta",
"Asymmetry parameter beta", this, beta),
130 _sigma(
"sigma",
"Width parameter sigma", this, argSigma),
131 _mu(
"mu",
"Location parameter mu", this, mu),
132 _a(
"a",
"Left tail location a", this,
a),
133 _n(
"n",
"Left tail parameter n", this,
n),
134 _a2(
"a2",
"Right tail location a2", this, a2),
135 _n2(
"n2",
"Right tail parameter n2", this, n2)
141 std::string(
"Lambda needs to be negative when ") +
_zeta.GetName() +
" is zero.");
152 _x(
"x", this, other.
_x),
157 _mu(
"mu", this, other.
_mu),
158 _a(
"a", this, other.
_a),
159 _n(
"n", this, other.
_n),
160 _a2(
"a2", this, other.
_a2),
161 _n2(
"n2", this, other.
_n2)
167const double logsq2pi = std::log(std::sqrt(
TMath::TwoPi()));
168const double ln2 = std::log(2.);
170double low_x_BK(
double nu,
double x){
171 return TMath::Gamma(nu)*std::pow(2., nu-1.)*std::pow(
x, -nu);
174double low_x_LnBK(
double nu,
double x){
175 return std::log(
TMath::Gamma(nu)) + ln2*(nu-1.) - std::log(
x) * nu;
178double besselK(
double ni,
double x) {
179 const double nu = std::abs(ni);
183 return low_x_BK(nu,
x);
188double LnBesselK(
double ni,
double x) {
189 const double nu = std::abs(ni);
193 return low_x_LnBK(nu,
x);
199double LogEval(
double d,
double l,
double alpha,
double beta,
double delta) {
200 const double gamma = alpha;
201 const double dg = delta*
gamma;
202 const double thing = delta*delta +
d*
d;
203 const double logno =
l*std::log(gamma/delta) - logsq2pi - LnBesselK(
l, dg);
205 return std::exp(logno + beta*
d
206 + (0.5-
l)*(std::log(alpha)-0.5*std::log(thing))
207 + LnBesselK(
l-0.5, alpha*std::sqrt(thing)) );
212double diff_eval(
double d,
double l,
double alpha,
double beta,
double delta){
213 const double gamma = alpha;
214 const double dg = delta*
gamma;
216 const double thing = delta*delta +
d*
d;
217 const double sqrthing = std::sqrt(thing);
218 const double alphasq = alpha*sqrthing;
219 const double no = std::pow(gamma/delta,
l)/besselK(
l, dg)*sq2pi_inv;
220 const double ns1 = 0.5-
l;
222 return no * std::pow(alpha, ns1) * std::pow(thing,
l/2. - 1.25)
223 * ( -
d * alphasq * (besselK(
l - 1.5, alphasq)
224 + besselK(
l + 0.5, alphasq))
225 + (2.*(
beta*thing +
d*
l) -
d) * besselK(ns1, alphasq) )
226 * std::exp(beta*
d) * 0.5;
229double Gauss2F1(
double a,
double b,
double c,
double x){
230 if (std::abs(
x) <= 1.) {
237double stIntegral(
double d1,
double delta,
double l){
238 return d1 * Gauss2F1(0.5, 0.5-
l, 3./2, -d1*d1/(delta*delta));
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) {
323 const auto N = output.size();
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]);
373 output[i] = A*std::pow(B-
d, -
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);
418void compute(std::span<double> output, std::span<const double>
x,
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) {
422 const auto N = output.size();
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) {
518 &&
_lambda.max() < 0.)
return 1;
527 auto& logstream =
coutF(Integration) <<
"When the PDF " <<
GetName()
528 <<
" was constructed, beta,zeta were 0, lambda<0 and all three were constant.\n"
529 <<
"This allowed for analytic integration, but now, numeric integration would be required.\n"
530 <<
"These parameters must either be kept constant, or be floating from the beginning. "
531 <<
" Terminating fit ..."
538 throw std::runtime_error(
"RooHypatia2 cannot be integrated analytically since parameters changed.");
544 constexpr double beta = 0.;
545 constexpr double cons1 = 1.;
548 throw std::logic_error(
"Trying to compute analytic integral with unknown configuration.");
553 const double d0 =
_x.min(rangeName) -
_mu;
554 const double d1 =
_x.max(rangeName) -
_mu;
564 const double deltaSq = delta*delta;
566 if ((d0 > -asigma) && (d1 < a2sigma)) {
567 return stIntegral(d1, delta,
_lambda) - stIntegral(d0, delta,
_lambda);
571 const double phi = 1. + a2sigma*a2sigma/deltaSq;
572 const double k1 = cons1*std::pow(phi,
_lambda-0.5);
573 const double k2 = beta*k1+ cons1*(
_lambda-0.5)*std::pow(phi,
_lambda-1.5)*2.*a2sigma/deltaSq;
574 const double B = -a2sigma -
_n2*k1/k2;
575 const double A = k1*std::pow(B+a2sigma,
_n2);
576 return A*(std::pow(B+d1,1-
_n2)/(1-
_n2) -std::pow(B+d0,1-
_n2)/(1-
_n2) ) ;
581 const double phi = 1. + asigma*asigma/deltaSq;
582 const double k1 = cons1*std::pow(phi,
_lambda-0.5);
583 const double k2 = beta*k1- cons1*(
_lambda-0.5)*std::pow(phi,
_lambda-1.5)*2*asigma/deltaSq;
584 const double B = -asigma +
_n*k1/k2;
585 const double A = k1*std::pow(B+asigma,
_n);
586 const double I0 = A*std::pow(B-d0,1-
_n)/(
_n-1);
587 const double I1 = A*std::pow(B-d1,1-
_n)/(
_n-1);
596 const double phi = 1. + asigma*asigma/deltaSq;
597 const double k1 = cons1*std::pow(phi,
_lambda-0.5);
598 const double k2 = beta*k1- cons1*(
_lambda-0.5)*std::pow(phi,
_lambda-1.5)*2*asigma/deltaSq;
599 const double B = -asigma +
_n*k1/k2;
600 const double A = k1*std::pow(B+asigma,
_n);
601 I0 = A*std::pow(B-d0,1-
_n)/(
_n-1);
602 I1a = A*std::pow(B+asigma,1-
_n)/(
_n-1) - stIntegral(-asigma, delta,
_lambda);
605 I0 = stIntegral(d0, delta,
_lambda);
609 const double phi = 1. + a2sigma*a2sigma/deltaSq;
610 const double k1 = cons1*std::pow(phi,
_lambda-0.5);
611 const double k2 = beta*k1+ cons1*(
_lambda-0.5)*std::pow(phi,
_lambda-1.5)*2.*a2sigma/deltaSq;
612 const double B = -a2sigma -
_n2*k1/k2;
613 const double A = k1*std::pow(B+a2sigma,
_n2);
614 I1b = A*(std::pow(B+d1,1-
_n2)/(1-
_n2) -std::pow(B+a2sigma,1-
_n2)/(1-
_n2) ) - stIntegral(d1, delta,
_lambda) + stIntegral(a2sigma,delta,
_lambda) ;
617 const double I1 = stIntegral(d1, delta,
_lambda) + I1a + I1b;
int Int_t
Signed integer 4 bytes (int).
bool isConstant() const
Check if the "Constant" attribute is set.
Int_t defaultPrintContents(Option_t *opt) const override
Define default RooPrinable print options for given Print() flag string For inline printing only show ...
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
RooAbsPdf()
Default constructor.
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
bool matchArgs(const RooArgSet &allDeps, RooArgSet &analDeps, const RooArgProxy &a, const Proxies &... proxies) const
RooArgSet is a container object that can hold multiple RooAbsArg objects.
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()
void doEval(RooFit::EvalContext &) const override
Base function for computing multiple values of a RooAbsReal.
double analyticalIntegral(Int_t code, const char *rangeName=nullptr) const override
Implements the actual analytical integral(s) advertised by getAnalyticalIntegral.
double evaluate() const override
Evaluate this PDF / function / constant. Needs to be overridden by all derived classes.
Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName=nullptr) const override
Interface function getAnalyticalIntergral advertises the analytical integrals that are supported.
virtual void printStream(std::ostream &os, Int_t contents, StyleOption style, TString indent="") const
Print description of object on ostream, printing contents set by contents integer,...
const char * GetName() const override
Returns name of object.
double beta(double x, double y)
Calculates the beta function.
double hyperg(double a, double b, double c, double x)
Calculates Gauss' hypergeometric 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()