39 ClassImp(RooNovosibirsk);
43 RooNovosibirsk::RooNovosibirsk(
const char *name,
const char *title,
44 RooAbsReal& _x, RooAbsReal& _peak,
45 RooAbsReal& _width, RooAbsReal& _tail) :
48 RooAbsPdf(name, title),
50 width(
"width",
"width",this,_width),
51 peak(
"peak",
"peak",this,_peak),
52 tail(
"tail",
"tail",this,_tail)
58 RooNovosibirsk::RooNovosibirsk(
const RooNovosibirsk& other,
const char *name):
59 RooAbsPdf(other,name),
61 width(
"width",this,other.width),
62 peak(
"peak",this,other.peak),
63 tail(
"tail",this,other.tail)
70 Double_t RooNovosibirsk::evaluate()
const
72 if (TMath::Abs(tail) < 1.e-7) {
73 return TMath::Exp( -0.5 * TMath::Power( ( (x - peak) / width ), 2 ));
76 Double_t arg = 1.0 - ( x - peak ) * tail / width;
83 Double_t log = TMath::Log(arg);
84 static const Double_t xi = 2.3548200450309494;
86 Double_t width_zero = ( 2.0 / xi ) * TMath::ASinH( tail * xi * 0.5 );
87 Double_t width_zero2 = width_zero * width_zero;
88 Double_t exponent = ( -0.5 / (width_zero2) * log * log ) - ( width_zero2 * 0.5 );
90 return TMath::Exp(exponent) ;
106 template<
class Tx,
class Tw
idth,
class Tpeak,
class Ttail>
107 void compute(
size_t batchSize,
double * __restrict output,
108 Tx X, Tpeak P, Twidth W, Ttail T)
110 constexpr
double xi = 2.3548200450309494;
111 for (
size_t i=0; i<batchSize; i++) {
112 double argasinh = 0.5*xi*T[i];
113 double argln = argasinh + 1/_rf_fast_isqrt(argasinh*argasinh +1);
114 double asinh = _rf_fast_log(argln);
116 double argln2 = 1 -(X[i]-P[i])*T[i]/W[i];
117 double ln = _rf_fast_log(argln2);
118 output[i] = ln/asinh;
119 output[i] *= -0.125*xi*xi*output[i];
120 output[i] -= 2.0/xi/xi*asinh*asinh;
124 for (
size_t i=0; i<batchSize; i++) {
125 output[i] = _rf_fast_exp(output[i]);
130 RooSpan<double> RooNovosibirsk::evaluateBatch(std::size_t begin, std::size_t batchSize)
const {
131 using namespace BatchHelpers;
133 EvaluateInfo info = getInfo( {&x, &peak, &width, &tail}, begin, batchSize );
134 if (info.nBatches == 0) {
137 auto output = _batchData.makeWritableBatchUnInit(begin, batchSize);
138 auto xData = x.getValBatch(begin, info.size);
140 if (info.nBatches==1 && !xData.empty()) {
141 compute(info.size, output.data(), xData.data(),
142 BracketAdapter<double> (peak),
143 BracketAdapter<double> (width),
144 BracketAdapter<double> (tail));
147 compute(info.size, output.data(),
148 BracketAdapterWithMask (x,x.getValBatch(begin,info.size)),
149 BracketAdapterWithMask (peak,peak.getValBatch(begin,info.size)),
150 BracketAdapterWithMask (width,width.getValBatch(begin,info.size)),
151 BracketAdapterWithMask (tail,tail.getValBatch(begin,info.size)));
158 Int_t RooNovosibirsk::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars,
const char* )
const
160 if (matchArgs(allVars,analVars,x))
return 1 ;
161 if (matchArgs(allVars,analVars,peak))
return 2 ;
170 Double_t RooNovosibirsk::analyticalIntegral(Int_t code,
const char* rangeName)
const
172 assert(code==1 || code==2) ;
177 static const Double_t sqrt2 = 1.4142135623730950;
178 static const Double_t sqlog2 = 0.832554611157697756;
179 static const Double_t sqlog4 = 1.17741002251547469;
180 static const Double_t log4 = 1.38629436111989062;
181 static const Double_t rootpiby2 = 1.2533141373155003;
182 static const Double_t sqpibylog2 = 2.12893403886245236;
185 Double_t A = x.min(rangeName);
186 Double_t B = x.max(rangeName);
192 if (TMath::Abs(tail) < 1.e-7) {
194 Double_t xscale = sqrt2*width;
196 result = rootpiby2*width*(TMath::Erf((B-peak)/xscale)-TMath::Erf((A-peak)/xscale));
203 Double_t log_argument_A = ( (peak - A)*tail + width ) / width ;
204 Double_t log_argument_B = ( (peak - B)*tail + width ) / width ;
207 if ( log_argument_A < 1.e-7) {
208 log_argument_A = 1.e-7;
212 if ( log_argument_B < 1.e-7) {
213 log_argument_B = 1.e-7;
216 Double_t term1 = TMath::ASinH( tail * sqlog4 );
217 Double_t term1_2 = term1 * term1;
220 Double_t erf_termA = ( term1_2 - log4 * TMath::Log( log_argument_A ) ) / ( 2 * term1 * sqlog2 );
221 Double_t erf_termB = ( term1_2 - log4 * TMath::Log( log_argument_B ) ) / ( 2 * term1 * sqlog2 );
223 result = 0.5 / tail * width * term1 * ( TMath::Erf(erf_termB) - TMath::Erf(erf_termA)) * sqpibylog2;
227 }
else if (code==2) {
228 Double_t A = x.min(rangeName);
229 Double_t B = x.max(rangeName);
235 if (TMath::Abs(tail) < 1.e-7) {
237 Double_t xscale = sqrt2*width;
239 result = rootpiby2*width*(TMath::Erf((B-x)/xscale)-TMath::Erf((A-x)/xscale));
246 Double_t log_argument_A = ( (A - x)*tail + width ) / width;
247 Double_t log_argument_B = ( (B - x)*tail + width ) / width;
250 if ( log_argument_A < 1.e-7) {
251 log_argument_A = 1.e-7;
255 if ( log_argument_B < 1.e-7) {
256 log_argument_B = 1.e-7;
259 Double_t term1 = TMath::ASinH( tail * sqlog4 );
260 Double_t term1_2 = term1 * term1;
263 Double_t erf_termA = ( term1_2 - log4 * TMath::Log( log_argument_A ) ) / ( 2 * term1 * sqlog2 );
264 Double_t erf_termB = ( term1_2 - log4 * TMath::Log( log_argument_B ) ) / ( 2 * term1 * sqlog2 );
266 result = 0.5 / tail * width * term1 * ( TMath::Erf(erf_termB) - TMath::Erf(erf_termA)) * sqpibylog2;
273 coutF(Eval) <<
"Error in RooNovosibirsk::analyticalIntegral" << std::endl;