52 using namespace BatchHelpers;
67 RooJohnson::RooJohnson(
const char *name,
const char *title,
68 RooAbsReal& mass, RooAbsReal& mu, RooAbsReal& lambda,
69 RooAbsReal& gamma, RooAbsReal& delta,
70 double massThreshold) :
71 RooAbsPdf(name,title),
72 _mass(
"mass",
"Mass observable", this, mass),
73 _mu(
"mu",
"Location parameter of the underlying normal distribution.", this, mu),
74 _lambda(
"lambda",
"Width parameter of the underlying normal distribution (=2 lambda)", this, lambda),
75 _gamma(
"gamma",
"Shift of transformation", this, gamma),
76 _delta(
"delta",
"Scale of transformation", this, delta),
77 _massThreshold(massThreshold)
79 RooHelpers::checkRangeOfParameters(
this, {&lambda, &delta}, 0.);
85 RooJohnson::RooJohnson(
const RooJohnson& other,
const char* newName) :
86 RooAbsPdf(other, newName),
87 _mass(
"Mass", this, other._mass),
88 _mu(
"mean", this, other._mu),
89 _lambda(
"lambda", this, other._lambda),
90 _gamma(
"gamma", this, other._gamma),
91 _delta(
"delta", this, other._delta),
92 _massThreshold(other._massThreshold)
100 double RooJohnson::evaluate()
const
102 if (_mass < _massThreshold)
105 const double arg = (_mass-_mu)/_lambda;
106 const double expo = _gamma + _delta * asinh(arg);
108 const double result = _delta
109 / sqrt(TMath::TwoPi())
110 / (_lambda * sqrt(1. + arg*arg))
111 * exp(-0.5 * expo * expo);
124 template<
class TMass,
class TMu,
class TLambda,
class TGamma,
class TDelta>
125 void compute(RooSpan<double> output, TMass mass, TMu mu, TLambda lambda, TGamma gamma,
126 TDelta delta,
double massThreshold) {
127 const int n = output.size();
129 const double sqrt_twoPi = sqrt(TMath::TwoPi());
131 for (
int i = 0; i < n; ++i) {
132 const double arg = (mass[i] - mu[i]) / lambda[i];
134 const double asinh_arg = _rf_fast_log(arg + std::sqrt(arg*arg+1));
136 const double asinh_arg = asinh(arg);
138 const double expo = gamma[i] + delta[i] * asinh_arg;
139 const double result = delta[i] / sqrt_twoPi
140 / (lambda[i] * std::sqrt(1. + arg*arg))
141 * _rf_fast_exp(-0.5 * expo * expo);
143 const double passThrough = mass[i] >= massThreshold;
144 output[i] = result * passThrough;
160 RooSpan<double> RooJohnson::evaluateBatch(std::size_t begin, std::size_t maxSize)
const {
161 auto massData = _mass.getValBatch(begin, maxSize);
162 auto muData = _mu.getValBatch(begin, maxSize);
163 auto lambdaData = _lambda.getValBatch(begin, maxSize);
164 auto gammaData = _gamma.getValBatch(begin, maxSize);
165 auto deltaData = _delta.getValBatch(begin, maxSize);
167 maxSize = std::min({massData, muData, lambdaData, gammaData, deltaData},
168 [](
const RooSpan<const double>& l,
const RooSpan<const double>& r){
169 return l.size() != 0 && l.size() < r.size();
176 auto output = _batchData.makeWritableBatchUnInit(begin, maxSize);
178 if (!massData.empty()
179 && (muData.empty() && lambdaData.empty() && gammaData.empty() && deltaData.empty())) {
180 compute(output, massData, BracketAdapter<double>(_mu),
181 BracketAdapter<double>(_lambda), BracketAdapter<double>(_gamma),
182 BracketAdapter<double>(_delta), _massThreshold);
186 BracketAdapterWithMask(_mass, massData),
187 BracketAdapterWithMask(_mu, muData),
188 BracketAdapterWithMask(_lambda, lambdaData),
189 BracketAdapterWithMask(_gamma, gammaData),
190 BracketAdapterWithMask(_delta, deltaData), _massThreshold);
198 int RooJohnson::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars,
const char* )
const
200 if (matchArgs(allVars, analVars, _mass))
return kMass;
201 if (matchArgs(allVars, analVars, _mu))
return kMean;
202 if (matchArgs(allVars, analVars, _lambda))
return kLambda;
203 if (matchArgs(allVars, analVars, _gamma))
return kGamma;
204 if (matchArgs(allVars, analVars, _delta))
return kDelta;
211 double RooJohnson::analyticalIntegral(Int_t code,
const char* rangeName)
const
216 const double globalNorm = 1.;
220 double min = -1.E300;
222 if (kMass <= code && code <= kLambda) {
223 double argMin, argMax;
226 argMin = (_mass.min(rangeName)-_mu)/_lambda;
227 argMax = (_mass.max(rangeName)-_mu)/_lambda;
228 }
else if (code == kMean) {
229 argMin = (_mass-_mu.min(rangeName))/_lambda;
230 argMax = (_mass-_mu.max(rangeName))/_lambda;
232 assert(code == kLambda);
233 argMin = (_mass-_mu)/_lambda.min(rangeName);
234 argMax = (_mass-_mu)/_lambda.max(rangeName);
237 min = _gamma + _delta * asinh(argMin);
238 max = _gamma + _delta * asinh(argMax);
239 }
else if (code == kGamma) {
240 const double arg = (_mass-_mu)/_lambda;
241 min = _gamma.min(rangeName) + _delta * asinh(arg);
242 max = _gamma.max(rangeName) + _delta * asinh(arg);
243 }
else if (code == kDelta) {
244 const double arg = (_mass-_mu)/_lambda;
245 min = _gamma + _delta.min(rangeName) * asinh(arg);
246 max = _gamma + _delta.max(rangeName) * asinh(arg);
257 const double ecmin = std::erfc(std::abs(min/sqrt(2.)));
258 const double ecmax = std::erfc(std::abs(max/sqrt(2.)));
260 const double result = 0.5 * (
261 min*max < 0.0 ? 2.0 - (ecmin + ecmax)
262 : max <= 0. ? ecmax - ecmin : ecmin - ecmax
266 return globalNorm * (result != 0. ? result : 1.E-300);
275 Int_t RooJohnson::getGenerator(
const RooArgSet& directVars, RooArgSet &generateVars, Bool_t )
const
277 if (matchArgs(directVars, generateVars, _mass))
return 1 ;
289 void RooJohnson::generateEvent(Int_t code)
293 const double gauss = RooRandom::randomGenerator()->Gaus(0., 1.);
294 const double mass = _lambda * sinh((gauss - _gamma)/_delta) + _mu;
295 if (_mass.min() <= mass && mass <= _mass.max() && _massThreshold <= mass) {
301 throw std::logic_error(
"Generation in other variables not yet implemented.");