CLHEP 2.4.6.4
C++ Class Library for High Energy Physics
Loading...
Searching...
No Matches
AnalyticConvolution.cc
Go to the documentation of this file.
1// -*- C++ -*-
2// $Id: AnalyticConvolution.cc,v 1.8 2010/07/22 21:55:10 garren Exp $
3#include "CLHEP/GenericFunctions/AbsFunction.hh"
4#include "CLHEP/GenericFunctions/AnalyticConvolution.hh"
5#include "CLHEP/GenericFunctions/Gaussian.hh"
6#include "CLHEP/GenericFunctions/Exponential.hh"
7#include <cmath> // for isfinite
8#if (defined _WIN32)
9#include <float.h> // Visual C++ _finite
10#endif
11#include <iostream>
12
13namespace Genfun {
14FUNCTION_OBJECT_IMP(AnalyticConvolution)
15
17 _lifetime ("Lifetime", 1.0, 0.0), // Bounded from below by zero, by default
18 _frequency("Frequency", 0.0, 0.0), // Bounded from below by zero, by default
19 _sigma ("Sigma", 1.0, 0.0), // Bounded from below by zero, by default
20 _offset ("Offset", 0.0), // Offset is unbounded
21 _type(type)
22{
23}
24
26 AbsFunction(right),
27 _lifetime (right._lifetime),
28 _frequency (right._frequency),
29 _sigma (right._sigma),
30 _offset (right._offset),
31 _type(right._type)
32{
33}
34
36}
37
39 return _frequency;
40}
41
43 return _frequency;
44}
45
47 return _lifetime;
48}
49
51 return _lifetime;
52}
53
55 return _sigma;
56}
57
59 return _sigma;
60}
61
63 return _offset;
64}
65
67 return _offset;
68}
69double AnalyticConvolution::operator() (double argument) const {
70 // Fetch the paramters. This operator does not convolve numerically.
71 static const double sqrtTwo = sqrt(2.0);
72 double xsigma = _sigma.getValue();
73 double tau = _lifetime.getValue();
74 double xoffset = _offset.getValue();
75 double x = argument-xoffset;
76 double freq = _frequency.getValue();
77
78 // smeared exponential an its asymmetry.
79 double expG=0.0, asymm=0.0;
80
81 if (_type==SMEARED_NEG_EXP) {
82 expG = exp((xsigma*xsigma +2*tau*(/*xoffset*/x))/(2.0*tau*tau)) *
83 erfc((xsigma*xsigma+tau*(/*xoffset*/x))/(sqrtTwo*xsigma*tau))/(2.0*tau);
84#if (defined _WIN32)
85 if (!_finite(expG)) {
86 expG=0.0;
87 }
88#else
89 if (!std::isfinite(expG)) {
90 expG=0.0;
91 }
92#endif
93 return expG;
94 }
95 else {
96 expG = exp((xsigma*xsigma +2*tau*(/*xoffset*/-x))/(2.0*tau*tau)) *
97 erfc((xsigma*xsigma+tau*(/*xoffset*/-x))/(sqrtTwo*xsigma*tau))/(2.0*tau);
98 }
99
100 // Both sign distribution=> return smeared exponential:
101 if (_type==SMEARED_EXP) {
102#if (defined _WIN32)
103 if (!_finite(expG)) {
104 expG=0.0;
105 }
106#else
107 if (!std::isfinite(expG)) {
108 expG=0.0;
109 }
110#endif
111 return expG;
112 }
113
114
115 // Calcualtion of asymmetry:
116
117 // First, if the mixing frequency is too high compared with the lifetime, we
118 // cannot see this oscillation. We abandon the complicated approach and just do
119 // this instead:
120 if (xsigma>6.0*tau) {
121 asymm = expG*(1/(1+tau*tau*freq*freq));
122 }
123 else if (xsigma==0.0) {
124 if (_type==SMEARED_COS_EXP|| _type==MIXED || _type==UNMIXED ) {
125 if (x>=0) asymm= (expG*cos(freq*x));
126 }
127 else if (_type==SMEARED_SIN_EXP) {
128 if (x>=0) asymm= (expG*sin(freq*x));
129 }
130 }
131 else {
132 std::complex<double> z(freq*xsigma/sqrtTwo, (xsigma/tau-x/xsigma)/sqrtTwo);
133 if (x<0) {
134 if (_type==SMEARED_COS_EXP|| _type==MIXED || _type==UNMIXED ) {
135 asymm= 2.0*nwwerf(z).real()/tau/4.0*exp(-x*x/2.0/xsigma/xsigma);
136 }
137 else if (_type==SMEARED_SIN_EXP) {
138 asymm= 2.0*nwwerf(z).imag()/tau/4.0*exp(-x*x/2.0/xsigma/xsigma);
139 }
140 }
141 else {
142 if (_type==SMEARED_COS_EXP||_type==MIXED || _type==UNMIXED) {
143 asymm= -2.0*nwwerf(std::conj(z)).real()/tau/4*exp(-x*x/2.0/xsigma/xsigma) +
144 exp(xsigma*xsigma/2 *(1/tau/tau - freq*freq) - x/tau)*(1./tau)*cos(freq*x - freq/tau*xsigma*xsigma);
145 }
146 else if (_type==SMEARED_SIN_EXP) {
147 asymm= +2.0*nwwerf(std::conj(z)).imag()/tau/4*exp(-x*x/2.0/xsigma/xsigma) +
148 exp(xsigma*xsigma/2 *(1/tau/tau - freq*freq) - x/tau)*(1./tau)*sin(freq*x - freq/tau*xsigma*xsigma);
149 }
150 }
151 }
152
153 // Return either MIXED, UNMIXED, or ASYMMETRY function.
154 if (_type==UNMIXED) {
155 double retVal = (expG+asymm)/2.0;
156 if (retVal<0)
157 std::cerr
158 << "Warning in AnalyticConvolution: negative probablity"
159 << std::endl;
160 if (retVal<0)
161 std::cerr
162 << xsigma << ' ' << tau << ' ' << xoffset << ' '
163 << freq << ' '<< argument
164 << std::endl;
165 if (retVal<0)
166 std::cerr << retVal << std::endl;
167 return retVal;
168 }
169 else if (_type==MIXED) {
170 double retVal = (expG-asymm)/2.0;
171 if (retVal<0)
172 std::cerr
173 << "Warning in AnalyticConvolution: negative probablity"
174 << std::endl;
175 if (retVal<0)
176 std::cerr
177 << xsigma << ' ' << tau << ' ' << xoffset << ' '
178 << freq << ' ' << argument
179 << std::endl;
180 if (retVal<0)
181 std::cerr << retVal << std::endl;
182 return retVal;
183 }
184 else if (_type==SMEARED_COS_EXP || _type==SMEARED_SIN_EXP) {
185 return asymm;
186 }
187 else {
188 std::cerr
189 << "Unknown sign parity. State is not allowed"
190 << std::endl;
191 exit(0);
192 return 0.0;
193 }
194
195}
196
197double AnalyticConvolution::erfc(double x) const {
198// This is accurate to 7 places.
199// See Numerical Recipes P 221
200 double t, z, ans;
201 z = (x < 0) ? -x : x;
202 t = 1.0/(1.0+.5*z);
203 ans = t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+
204 t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+
205 t*(-0.82215223+t*0.17087277 ))) ))) )));
206 if ( x < 0 ) ans = 2.0 - ans;
207 return ans;
208}
209
210double AnalyticConvolution::pow(double x,int n) const {
211 double val=1;
212 for(int i=0;i<n;i++){
213 val=val*x;
214 }
215 return val;
216}
217
218std::complex<double> AnalyticConvolution::nwwerf(std::complex<double> z) const {
219 std::complex<double> zh,r[38],s,t,v;
220
221 const double z1 = 1;
222 const double hf = z1/2;
223 const double z10 = 10;
224 const double c1 = 74/z10;
225 const double c2 = 83/z10;
226 const double c3 = z10/32;
227 const double c4 = 16/z10;
228 const double c = 1.12837916709551257;
229 const double p = pow(2.0*c4,33);
230
231 double x=z.real();
232 double y=z.imag();
233 double xa=(x >= 0) ? x : -x;
234 double ya=(y >= 0) ? y : -y;
235 if(ya < c1 && xa < c2){
236 zh = std::complex<double>(ya+c4,xa);
237 r[37]= std::complex<double>(0,0);
238 // do 1 n = 36,1,-1
239 for(int n = 36; n>0; n--){
240 t=zh+double(n)*std::conj(r[n+1]);
241 r[n]=hf*t/std::norm(t);
242 }
243 double xl=p;
244 s=std::complex<double>(0,0);
245 // do 2 n = 33,1,-1
246 for(int k=33; k>0; k--){
247 xl=c3*xl;
248 s=r[k]*(s+xl);
249 }
250 v=c*s;
251 }
252 else{
253 zh=std::complex<double>(ya,xa);
254 r[1]=std::complex<double>(0,0);
255 // do 3 n = 9,1,-1
256 for(int n=9;n>0;n--){
257 t=zh+double(n)*std::conj(r[1]);
258 r[1]=hf*t/std::norm(t);
259 }
260 v=c*r[1];
261 }
262 if(ya == 0) v= std::complex<double>(exp(-xa*xa),v.imag());
263 if(y < 0) {
264 v=2.0*std::exp(std::complex<double>(-xa,-ya)*std::complex<double>(xa,ya))-v;
265 if(x > 0) v=std::conj(v);
266 }
267 else{
268 if(x < 0) v=std::conj(v);
269 }
270 return v;
271}
272} // namespace Genfun
#define FUNCTION_OBJECT_IMP(classname)
Definition: AbsFunction.hh:149
AnalyticConvolution(Type=SMEARED_EXP)
virtual double operator()(double argument) const override
virtual double getValue() const
Definition: Parameter.cc:29
#define double(obj)
Definition: excDblThrow.cc:32
#define exit(x)
Definition: Abs.hh:14