All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OscCalcSterileApprox.cxx
Go to the documentation of this file.
2 
4 
5 #include "TMath.h"
6 
7 #include "Math/SpecFunc.h"
8 
9 #include <cassert>
10 #include <iostream>
11 #include <map>
12 
13 namespace ana
14 {
15  // --------------------------------------------------------------------------
17  {
19  fSinSq2ThetaEESet = true;
20  fSinSq2ThetaEE = t;
21  }
22 
23  // --------------------------------------------------------------------------
25  {
27  if(!fSinSq2ThetaMuMuSet && !fSinSq2ThetaMuESet) return 0;
28 
29  // The three angles are coupled via
30  //
31  // ss2thmm = 4*Um4^2*(1-Um4^2)
32  // ss2thee = 4*Ue4^2*(1-Ue4^2)
33  // ss2thme = 4*Um4^2*Ue4^2
34  //
35  // Solve for the final (nue survival angle). Emperically, choosing the
36  // negative sign in the expression works well.
37 
38  // A couple of limits
39  if(fSinSq2ThetaMuMu <= 0) return fSinSq2ThetaMuE / 4;
40  if(fSinSq2ThetaMuMu >= 1) return fSinSq2ThetaMuE / 2;
41 
42  // General case
43  const double Ue4sq = fSinSq2ThetaMuE/(2*fSinSq2ThetaMuMu)*(1-sqrt(1-fSinSq2ThetaMuMu));
44  assert(!isinf(Ue4sq) && !isnan(Ue4sq));
45  const double sinsq2thetaee = 4.0*Ue4sq*(1-Ue4sq);
46 
47  assert(sinsq2thetaee >= 0 && sinsq2thetaee <= 1);
48 
49  // Cross-check that we actually solved the equations correctly
50  if(Ue4sq > 0){
51  const double Umu4sq = fSinSq2ThetaMuE/(4*Ue4sq);
52  assert(fabs(4*Umu4sq*(1-Umu4sq) - fSinSq2ThetaMuMu) < 1e-6);
53  }
54 
55  return sinsq2thetaee;
56  }
57 
58  // --------------------------------------------------------------------------
60  {
62  fSinSq2ThetaMuMuSet = true;
63  fSinSq2ThetaMuMu = t;
64  }
65 
66  // --------------------------------------------------------------------------
68  {
70  if(!fSinSq2ThetaEESet && !fSinSq2ThetaMuESet) return 0;
71 
72  // The three angles are coupled via
73  //
74  // ss2thmm = 4*Um4^2*(1-Um4^2)
75  // ss2thee = 4*Ue4^2*(1-Ue4^2)
76  // ss2thme = 4*Um4^2*Ue4^2
77  //
78  // Solve for the final (numu survival angle). Emperically, choosing the
79  // negative sign in the expression works well.
80 
81  // A couple of limits
82  if(fSinSq2ThetaEE <= 0) return fSinSq2ThetaMuE / 4;
83  if(fSinSq2ThetaEE >= 1) return fSinSq2ThetaMuE / 2;
84 
85  // General case
86  const double Um4sq = fSinSq2ThetaMuE/(2*fSinSq2ThetaEE)*(1-sqrt(1-fSinSq2ThetaEE));
87  assert(!isinf(Um4sq) && !isnan(Um4sq));
88  const double sinsq2thetamm = 4.0*Um4sq*(1-Um4sq);
89 
90  assert(sinsq2thetamm >= 0 && sinsq2thetamm <= 1);
91 
92  // Cross-check that we actually solved the equations correctly
93  if(Um4sq > 0){
94  const double Ue4sq = fSinSq2ThetaMuE/(4*Um4sq);
95  assert(fabs(4*Ue4sq*(1-Ue4sq) - fSinSq2ThetaEE) < 1e-6);
96  }
97 
98  return sinsq2thetamm;
99  }
100 
101  // --------------------------------------------------------------------------
103  {
105  fSinSq2ThetaMuESet = true;
106  fSinSq2ThetaMuE = t;
107  }
108 
109  // --------------------------------------------------------------------------
111  {
113  if(!fSinSq2ThetaMuMuSet && !fSinSq2ThetaEESet) return 0;
114 
115  // The three angles are coupled via
116  //
117  // ss2thmm = 4*Um4^2*(1-Um4^2)
118  // ss2thee = 4*Ue4^2*(1-Ue4^2)
119  // ss2thme = 4*Um4^2*Ue4^2
120  //
121  // Choose 1-sqrt() case instead of 1+sqrt() since in the later
122  // if both ss2thmm and ss2thee are 0 we stil get ss2thme = 1,
123  // which seems wrong.
124 
125  const double Um4sq = 0.5 * (1.0 - std::sqrt(1.0 - fSinSq2ThetaMuMu));
126  const double Ue4sq = 0.5 * (1.0 - std::sqrt(1.0 - fSinSq2ThetaEE));
127 
128  assert(!isinf(Um4sq) && !isnan(Um4sq));
129  assert(!isinf(Ue4sq) && !isnan(Ue4sq));
130  const double sinsq2thetame = 4.0*Um4sq*Ue4sq;
131 
132  assert(sinsq2thetame >= 0 && sinsq2thetame <= 1);
133 
134  return sinsq2thetame;
135  }
136 
137  // --------------------------------------------------------------------------
138  double Si(double x)
139  {
140  if(isinf(x)) return TMath::Pi()/2;
141  return ROOT::Math::sinint(x);
142  }
143 
144  // --------------------------------------------------------------------------
145  double AvgSinSq(double k, double a, double b)
146  {
147  // This function shows up high in profiles, and is often called with the same masses/baselines/energies
148  static std::map<std::tuple<double, double, double>, double> cache;
149  const std::tuple<double, double, double> key = {k, a, b};
150 
151  // energies times masses times baselines plus some slack
152  if(cache.size() > 100*100*10) cache.clear();
153 
154  auto it = cache.find(key);
155  if(it != cache.end()) return it->second;
156 
157  double ret = 0;
158  if(a == b){
159  ret = util::sqr(sin(k/a));
160  }
161  else{
162  // https://www.wolframalpha.com/input/?i=integral+sin%5E2(k%2Fx)+from+a+to+b
163  ret = k*(Si(2*k/a)-Si(2*k/b));
164  assert(!isnan(ret));
165  if(a) ret -= a * util::sqr(sin(k/a));
166  assert(!isnan(ret));
167  if(b) ret += b * util::sqr(sin(k/b));
168  assert(!isnan(ret));
169 
170  ret /= (b-a);
171  }
172 
173  cache[key] = ret;
174  return ret;
175  }
176 
177  // --------------------------------------------------------------------------
178  double OscCalcSterileApprox::P(int from, int to, double E)
179  {
180  return P_range(from, to, E, E);
181  }
182 
183  // --------------------------------------------------------------------------
184  double OscCalcSterileApprox::PFromDelta(int from, int to, double Delta) const
185  {
186  if(abs(from) == 14 && abs(to) == 14){
187  return 1-GetSinSq2ThetaMuMu()*Delta;
188  }
189  else if(abs(from) == 12 && abs(to) == 12){
190  return 1-GetSinSq2ThetaEE()*Delta;
191  }
192  else if(abs(from) == 14 && abs(to) == 12){
193  return GetSinSq2ThetaMuE()*Delta;
194  }
195  else if(abs(from) == 12 && abs(to) == 14){
196  // TODO - this seems reasonable, is it right?
197  return GetSinSq2ThetaMuE()*Delta;
198  }
199  else if(abs(to) == 16){ // no tau appearance
200  return 0;
201  }
202 
203  //Option to return the active fraction
204  else if (abs(from) == 14 && to == 0) {
205  return (1-GetSinSq2ThetaMuMu()*Delta) + (GetSinSq2ThetaMuE()*Delta);
206  }
207  else if (abs(from) == 12 && to == 0) {
208  return (1-GetSinSq2ThetaEE()*Delta) + (GetSinSq2ThetaMuE()*Delta);
209  }
210 
211  std::cout << "OscCalcSterileApprox: P(" << from << ", " << to << ") not implemented" << std::endl;
212  abort();
213  }
214 
215  // --------------------------------------------------------------------------
216  double OscCalcSterileApprox::P_range(int from, int to, double Elo, double Ehi)
217  {
218  if(Ehi <= 0) return 0;
219 
220  if(fDmsq == 0) return (from == to || to == 0) ? 1 : 0;
221 
222  Elo = std::max(0., Elo);
223 
224  assert(fL != 0);
225  const double Delta = AvgSinSq(1.267*fDmsq*fL, Elo, Ehi);
226  assert(!isnan(Delta));
227 
228  return PFromDelta(from, to, Delta);
229  }
230 
231  // --------------------------------------------------------------------------
233  double LElo, double LEhi)
234  {
235  if(fDmsq == 0) return (from == to || to == 0) ? 1 : 0;
236 
237  LElo = std::max(0., LElo);
238 
239  LElo *= 1.267*fDmsq;
240  LEhi *= 1.267*fDmsq;
241 
242  if(LElo == LEhi) return PFromDelta(from, to, util::sqr(sin(LElo)));
243 
244  // Average value of sin^2 over the range
245  const double Delta = (.25*(sin(2*LElo) - sin(2*LEhi)) + .5*(LEhi - LElo))/(LEhi-LElo);
246  assert(!isnan(Delta));
247 
248  return PFromDelta(from, to, Delta);
249  }
250 
251  // --------------------------------------------------------------------------
253  {
255 
256  ret->fDmsq = fDmsq;
266  ret->fL = fL;
267 
268  return ret;
269  }
270 
271  //---------------------------------------------------------------------------
273  {
274  TMD5* ret = new TMD5;
275  const std::string txt = "SterileApprox";
276  ret->Update((unsigned char*)txt.c_str(), txt.size());
277  const int kNumParams = 4;
278  double angles[2] = {0, 0};
279  int angles_set = 0;
280  if(fSinSq2ThetaMuMuSet && angles_set < 2)
281  angles[angles_set++] = fSinSq2ThetaMuMu;
282  if(fSinSq2ThetaMuESet && angles_set < 2)
283  angles[angles_set++] = fSinSq2ThetaMuE;
284  if(fSinSq2ThetaEESet && angles_set < 2)
285  angles[angles_set++] = fSinSq2ThetaEE;
286  double buf[kNumParams] = {fDmsq, angles[0], angles[1], fL};
287  ret->Update((unsigned char*)buf, sizeof(double)*kNumParams);
288  ret->Final();
289  return ret;
290  }
291 
292  //---------------------------------------------------------------------------
294  {
295  auto ret = new OscCalcSterileApproxAdjustable;
296  ret->calc.SetDmsq(0);
298  ret->calc.SetSinSq2ThetaMuMu(0);
300  ret->calc.SetSinSq2ThetaMuE(0);
302  ret->calc.SetSinSq2ThetaEE(0);
303  ret->calc.SetL(0); // make clear this is uninitialized
304 
305  return ret;
306  }
307 
308  //---------------------------------------------------------------------------
309  const OscCalcSterileApprox* DowncastToSterileApprox(const osc::IOscCalc* calc, bool allowFail)
310  {
311  const OscCalcSterileApprox* ret1
312  = dynamic_cast<const OscCalcSterileApprox*>(calc);
313  if(ret1) return ret1;
314 
316  = dynamic_cast<const OscCalcSterileApproxAdjustable*>(calc);
317  if(ret2) return &ret2->calc;
318 
319  if(allowFail) return 0;
320 
321  std::cout << "Calculator was not of type OscCalcSterileApprox." << std::endl;
322  abort();
323  }
324 
325  //---------------------------------------------------------------------------
327  bool allowFail)
328  {
330  = dynamic_cast<OscCalcSterileApprox*>(calc);
331  if(ret1) return ret1;
332 
334  = dynamic_cast<OscCalcSterileApproxAdjustable*>(calc);
335  if(ret2) return &ret2->calc;
336 
337  if(allowFail) return 0;
338 
339  std::cout << "Calculator was not of type OscCalcSterileApprox." << std::endl;
340  abort();
341  }
342 
343 }
double P_LoverE(int from, int to, double LElo, double LEhi)
const OscCalcSterileApprox * DowncastToSterileApprox(const osc::IOscCalc *calc, bool allowFail)
process_name opflash particleana ie x
process_name E
process_name opflashCryoW ana
T sqr(T x)
More efficient square function than pow(x,2)
Definition: MathUtil.h:23
process_name gaushit a
T abs(T value)
double PFromDelta(int from, int to, double Delta) const
OscCalcSterileApproxAdjustable * DefaultSterileApproxCalc(SterileOscAngles angles)
virtual OscCalcSterileApprox * Copy() const override
virtual double P(int from, int to, double E) override
double AvgSinSq(double k, double a, double b)
do i e
double P_range(int from, int to, double Elo, double Ehi)
pdgs k
Definition: selectors.fcl:22
double Si(double x)
TMD5 * GetParamsHash() const override
BEGIN_PROLOG could also be cout