OscCalculatorGeneral.cxx
Go to the documentation of this file.
1 
2 // \file OscCalculatorGeneral.cxx
3 // \brief Source file for general oscillation calculation
4 // \version $Id: OscCalculatorGeneral.cxx,v 1.1 2013/10/17 22:18:11 ljf26 Exp $
5 // \author
6 #include "OscLib/func/OscCalculatorGeneral.h"
7 
8 #include <boost/numeric/ublas/vector.hpp>
9 #include <boost/numeric/ublas/matrix.hpp>
10 
11 #include <vector>
12 
13 #include <cassert>
14 #include <complex>
15 
16 namespace osc
17 {
18  const unsigned int kNumFlavours = 3;
19 
20  namespace ublas = boost::numeric::ublas;
21  typedef std::complex<double> val_t;
22  typedef ublas::bounded_array<val_t, kNumFlavours> alloc_t;
23  // Should be a c_matrix, but get ambiguity in triple multiplication
24  typedef ublas::bounded_matrix<val_t, kNumFlavours, kNumFlavours> ComplexMat;
25  typedef ublas::c_vector<val_t, kNumFlavours> ComplexVec;
26  typedef ublas::unit_vector<val_t, alloc_t> UnitVec;
27  const ublas::zero_matrix<val_t, alloc_t> kZeroMat(kNumFlavours, kNumFlavours);
28  const ublas::identity_matrix<val_t, alloc_t> kIdentity(kNumFlavours);
29 
30  // Private data. Doing it this way avoids having to expose complex numbers,
31  // matrices etc. to the user.
33  {
34  Priv() :
38  pmns(kZeroMat),
39  dirty(true)
40  {
41  }
42 
43  double c13, s13;
44  std::complex<double> phase;
45 
46  ComplexMat atmos, react, solar;
47  ComplexMat pmns;
48 
49  bool dirty;
50  };
51 
52 
55  {
56  }
57 
59  {
60  delete d;
61  }
62 
63 
65  {
66  fTh23 = th23;
67  d->atmos(2, 2) = d->atmos(1, 1) = cos(th23);
68  d->atmos(1, 2) = sin(th23);
69  d->atmos(2, 1) = -d->atmos(1, 2);
70  d->dirty = true;
71  }
72 
74  {
75  fTh13 = th13;
76  d->c13 = cos(th13);
77  d->s13 = sin(th13);
78 
79  d->react(2, 2) = d->react(0, 0) = d->c13;
80  d->react(0, 2) = d->s13*d->phase;
81  d->react(2, 0) = -std::conj(d->react(0, 2));
82  d->dirty = true;
83  }
84 
86  {
87  fTh12 = th12;
88  d->solar(1, 1) = d->solar(0, 0) = cos(th12);
89  d->solar(0, 1) = sin(th12);
90  d->solar(1, 0) = -d->solar(0, 1);
91  d->dirty = true;
92  }
93 
94  void OscCalculatorGeneral::SetdCP(double delta)
95  {
96  fdCP = delta;
97 
98  d->phase = std::polar(1.0, -delta);
99 
100  d->react(2, 2) = d->react(0, 0) = d->c13;
101  d->react(0, 2) = d->s13*d->phase;
102  d->react(2, 0) = -std::conj(d->react(0, 2));
103  d->dirty = true;
104  }
105 
107  {
108  if(d->dirty){
109  ublas::noalias(d->pmns) = ublas::prod(d->atmos, ublas::prod<ComplexMat>(d->react, d->solar));
110  d->dirty = false;
111  }
112  return d->pmns;
113  }
114 
115 
116  // U is the PMNS matrix
117  // mSq are the squared masses. Pick an arbitrary zero and use the dmsqs
118  // E is the neutrino energy
119  ComplexMat VacuumHamiltonian(const ComplexMat& U, std::vector<double> mSq, double E)
120  {
121  // Conversion factor for units
122  E /= 4*1.267;
123 
124  assert(mSq.size() == kNumFlavours);
125 
126  ComplexMat H = kZeroMat;
127 
128  // Loop over rows and columns of the output
129  for(unsigned int a = 0; a < kNumFlavours; ++a){
130  for(unsigned int b = 0; b < kNumFlavours; ++b){
131  // Form sum over mass states
132  for(unsigned int i = 0; i < kNumFlavours; ++i){
133  H(a, b) += U(a, i)*mSq[i]/(2*E)*std::conj(U(b, i));
134  }
135  }
136  }
137 
138  return H;
139  }
140 
141 
142  // This is calculated assuming matter neutrinos. So far, this can simply be
143  // converted to antineutrinos by taking a minus sign.
144  ComplexMat MatterHamiltonianComponent(double Ne, double emutau)
145  {
146  // Need to convert avogadro's constant so that the total term comes out in
147  // units of inverse distance. Note that Ne will be specified in g/cm^-3
148  // I put the following into Wolfram Alpha:
149  // (fermi coupling constant)*((avogadro number)/cm^3)*(reduced planck constant)^2*(speed of light)^2
150  // And then multiplied by 1000 because we specify L in km not m.
151  const double GF = 1.368e-4;
152 
153  ComplexMat H = kZeroMat;
154 
155  H(0, 0) = sqrt(2)*GF*Ne;
156 
157  // Ignoring conjugates here because we assume e_mutau is real
158  H(1, 2) = H(2, 1) = emutau*sqrt(2)*GF*Ne;
159 
160  return H;
161  }
162 
163 
164  /* TODO: maybe look at
165  http://en.wikipedia.org/wiki/Baker%E2%80%93Campbell%E2%80%93Hausdorff_formula
166  and
167  http://en.wikipedia.org/wiki/Pad%C3%A9_approximant
168  http://en.wikipedia.org/wiki/Pad%C3%A9_table
169  */
170  ComplexMat MatrixExp(const ComplexMat& m2)
171  {
172  // We use the identity e^(a*b) = (e^a)^b
173  // First: ensure the exponent is really small, 65536 = 2^16
174  ComplexMat m = m2/65536;
175 
176  // To first order e^x = 1+x
177  ComplexMat ret = kIdentity+m;
178 
179  // Raise the result to the power 65536, by squaring it 16 times
180  for(int n = 0; n < 16; ++n) ret = ublas::prod(ret, ret);
181 
182  return ret;
183  }
184 
185 
186  ComplexVec EvolveState(ComplexVec A, const ComplexMat& H, double L)
187  {
188  const std::complex<double> i = std::complex<double>(0, 1);
189 
190  return ublas::prod(MatrixExp(-H*L*i), A);
191  }
192 
193  void conjugate_elements(ComplexMat& m)
194  {
195  for(unsigned int i = 0; i < kNumFlavours; ++i)
196  for(unsigned int j = 0; j < kNumFlavours; ++j)
197  m(i, j) = std::conj(m(i, j));
198  }
199 
200  double OscCalculatorGeneral::P(int from, int to, double E)
201  {
202  const int af = abs(from);
203  const int at = abs(to);
204  assert(af == 12 || af == 14 || af == 16);
205  assert(at == 12 || at == 14 || at == 16);
206 
207  // No matter<->antimatter transitions
208  if(af*at < 0) return 0;
209 
210  ComplexMat U = GetPMNS(d);
211  // P(a->b|U) = P(abar->bbar|U*)
212  if(from < 0) conjugate_elements(U);
213 
214  ComplexVec initState = UnitVec(kNumFlavours, 1); // Display accelerator bias
215  if(af == 12) initState = UnitVec(kNumFlavours, 0);
216  if(af == 16) initState = UnitVec(kNumFlavours, 2);
217 
218  std::vector<double> mSq;
219  mSq.push_back(0);
220  mSq.push_back(fDmsq21);
221  mSq.push_back(fDmsq21 + fDmsq32);
222 
223  ComplexMat H = VacuumHamiltonian(U, mSq, E);
224  ComplexMat Hm = MatterHamiltonianComponent(fRho, fEMuTau);
225  // So far, contribution to the antineutrino Hamiltonian is just the negative
226  // If there were to be any complex stuff here, would have to think about
227  // how it transformed with antineutrinos.
228  if(from < 0) H += -1*Hm; else H += Hm;
229 
230  ComplexVec finalState = EvolveState(initState, H, fL);
231 
232  if(at == 12) return std::norm(finalState(0));
233  if(at == 14) return std::norm(finalState(1));
234  if(at == 16) return std::norm(finalState(2));
235 
236  assert(0 && "Not reached");
237  }
238 
239 } // namespace
ComplexMat MatrixExp(const ComplexMat &m2)
void conjugate_elements(ComplexMat &m)
ublas::unit_vector< val_t, alloc_t > UnitVec
virtual void SetTh13(double th13)
virtual double P(int from, int to, double E)
ComplexVec EvolveState(ComplexVec A, const ComplexMat &H, double L)
T abs(T value)
ComplexMat GetPMNS(OscCalculatorGeneral::Priv *d)
virtual void SetTh23(double th23)
virtual void SetdCP(double dCP)
ublas::bounded_matrix< val_t, kNumFlavours, kNumFlavours > ComplexMat
ComplexMat VacuumHamiltonian(const ComplexMat &U, std::vector< double > mSq, double E)
Definition: EarthModel.h:12
auto norm(Vector const &v)
Return norm of the specified vector.
const ublas::zero_matrix< val_t, alloc_t > kZeroMat(kNumFlavours, kNumFlavours)
const unsigned int kNumFlavours
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
std::complex< double > val_t
ComplexMat MatterHamiltonianComponent(double Ne, double emutau)
E
Definition: 018_def.c:13
static bool * b
Definition: config.cpp:1043
ublas::c_vector< val_t, kNumFlavours > ComplexVec
const ublas::identity_matrix< val_t, alloc_t > kIdentity(kNumFlavours)
ublas::bounded_array< val_t, kNumFlavours > alloc_t
virtual void SetTh12(double th12)