PMNS.cxx
Go to the documentation of this file.
1 
2 // $Id: PMNS.cxx,v 1.1 2013/10/17 22:18:11 ljf26 Exp $
3 //
4 // Implementation of oscillations of neutrinos in matter in an
5 // three-neutrino framework based on the following reference:
6 //
7 //......................................................................
8 //
9 // PHYSICAL REVIEW D VOLUME 22, NUMBER 11 1 DECEMBER 1980
10 //
11 // Matter effects on three-neutrino oscillation
12 //
13 // V. Barger and K. Whisnant
14 // Physics Department, U. of Wisconsin, Madison, Wisconsin 53706
15 //
16 // S. Pakvasa
17 // Physics Department, U. of Hawaii at Manoa, Honolulu, Hawaii 96822
18 //
19 // R.J.N. Phillips
20 // Rutherford Laboratory, Chilton, Didcot, Oxon, England
21 // (Received 4 August 1980)
22 //
23 // 22 2718
24 // --
25 //......................................................................
26 //
27 // Throughout I have taken:
28 // - L to be the neutrino flight distance in km
29 // - E to be the neutrino energy in GeV
30 // - dmsqr to be the differences between the mass-squares in eV^2
31 // - Ne to be the electron number density in mole/cm^3
32 // - theta12,theta23,theta13,deltaCP to be in radians
33 //
34 // messier@indiana.edu
35 #include "PMNS.h"
36 #include <cstdlib>
37 #include <iostream>
38 #include <cassert>
39 using namespace osc;
40 
41 // Some useful complex numbers
42 static std::complex<double> zero(0.0,0.0);
43 static std::complex<double> one (1.0,0.0);
44 
45 // Unit conversion constants
46 static const double kK1 = 2.53386551601e-00;
47 static const double kK2 = 4.62711492217e-09;
48 static const double kGeV2eV = 1.0E9;
49 
50 //......................................................................
51 
53 {
54  this->SetMix(0.,0.,0.,0.);
55  this->SetDeltaMsqrs(0.,0.);
56  this->Reset();
57 }
58 
59 //......................................................................
60 
61 PMNS::PMNS(double th12, double th23, double th13, double deltacp,
62  double dms21, double dms32)
63 {
64  this->SetMix(th12, th23, th13, deltacp);
65  this->SetDeltaMsqrs(dms21, dms32);
66  this->Reset();
67 }
68 
69 //......................................................................
70 
71 void PMNS::DumpMatrix(const complex M[][3]) const
72 {
73  std::cout
74  <<"| "<<M[0][0]<<"\t"<<M[0][1]<<"\t"<<M[0][2]<<" |\n"
75  <<"| "<<M[1][0]<<"\t"<<M[1][1]<<"\t"<<M[1][2]<<" |\n"
76  <<"| "<<M[2][0]<<"\t"<<M[2][1]<<"\t"<<M[2][2]<<" |\n"
77  <<std::endl;
78 }
79 
80 //......................................................................
81 
82 void PMNS::PrintMix() const { this->DumpMatrix(fU); }
83 
84 //......................................................................
85 
86 void PMNS::SetMix(double th12, double th23, double th13, double deltacp)
87 {
88  register int i, j;
89  double s12, s23, s13, c12, c23, c13;
90  complex idelta(0.0,deltacp);
91 
92  s12 = sin(th12); s23 = sin(th23); s13 = sin(th13);
93  c12 = cos(th12); c23 = cos(th23); c13 = cos(th13);
94 
95  fU[0][0] = c12*c13;
96  fU[0][1] = s12*c13;
97  fU[0][2] = s13*exp(-idelta);
98 
99  fU[1][0] = -s12*c23-c12*s23*s13*exp(idelta);
100  fU[1][1] = c12*c23-s12*s23*s13*exp(idelta);
101  fU[1][2] = s23*c13;
102 
103  fU[2][0] = s12*s23-c12*c23*s13*exp(idelta);
104  fU[2][1] = -c12*s23-s12*c23*s13*exp(idelta);
105  fU[2][2] = c23*c13;
106 
107  // Compute derived forms of the mixing matrix
108  for (i=0; i<3; ++i) {
109  for (j=0; j<3; ++j) {
110  fUtran[i][j] = fU[j][i];
111  fUstar[i][j] = conj(fU[i][j]);
112  fUdagg[i][j] = conj(fU[j][i]);
113  }
114  }
115 }
116 
117 void PMNS::SetMixBWCP(double th1, double th2, double th3, double d)
118 {
119  int i, j;
120  double s1, s2, s3, c1, c2, c3;
121  complex id(0.0,d);
122  s1 = sin(th1); s2 = sin(th2); s3 = sin(th3);
123  c1 = cos(th1); c2 = cos(th2); c3 = cos(th3);
124 
125  fU[0][0] = c1;
126  fU[0][1] = s1*c3;
127  fU[0][2] = s1*s3;
128 
129  fU[1][0] = -s1*c2;
130  fU[1][1] = c1*c2*c3+s2*s3*exp(id);
131  fU[1][2] = c1*c2*s3-s2*c3*exp(id);
132 
133  fU[2][0] = -s1*s2;
134  fU[2][1] = c1*s2*c3-c2*s3*exp(id);
135  fU[2][2] = c1*s2*s3+c2*c3*exp(id);
136 
137  // Compute derived forms of the mixing matrix
138  for (i=0; i<3; ++i) {
139  for (j=0; j<3; ++j) {
140  fUtran[i][j] = fU[j][i];
141  fUstar[i][j] = conj(fU[i][j]);
142  fUdagg[i][j] = conj(fU[j][i]);
143  }
144  }
145 }
146 
147 //......................................................................
148 
150 {
151  std::cout
152  <<"|"<<fdmsqr[0][0]<<"\t"<<fdmsqr[0][1]<<"\t"<<fdmsqr[0][2]<<"|\n"
153  <<"|"<<fdmsqr[1][0]<<"\t"<<fdmsqr[1][1]<<"\t"<<fdmsqr[1][2]<<"|\n"
154  <<"|"<<fdmsqr[2][0]<<"\t"<<fdmsqr[2][1]<<"\t"<<fdmsqr[2][2]<<"|"
155  << std::endl;
156 }
157 
158 //......................................................................
159 void PMNS::SetDeltaMsqrs(double dm21, double dm32)
160 {
161  double eps = 5.0E-9;
162  double msqr[3];
163 
164  msqr[0] = 0.0;
165  msqr[1] = dm21;
166  msqr[2] = dm21+dm32;
167 
168  // Degeneracies cause problems with diagonalization, so break them
169  // ever so slightly
170  if (dm21==0.0) {msqr[0] -= 0.5*eps; msqr[1] += 0.5*eps; }
171  if (dm32==0.0) {msqr[1] -= 0.5*eps; msqr[2] += 0.5*eps; }
172 
173  // Assign the mass splittings fdmsqr_ij = msqr_i - msqr_j by
174  // convention
175  for (register int i=0; i<3; ++i) {
176  for (register int j=0; j<3; ++j) {
177  // A somewhat subtle point: Barger et al. refer to the sign of
178  // m1-m2 being positive which implies dm^2_12>0 and
179  // dm^2_21<0. The labeling in more common use is to assume m3 is
180  // heaviest such that dm_12<0 and dm_21>0. Rather than reverse
181  // all the indices in all the equations, flip the signs here.
182  fdmsqr[i][j] = -(msqr[i] - msqr[j]);
183  }
184  }
185 }
186 
187 //......................................................................
188 void PMNS::Multi(complex A[][3], const complex B[][3], const complex C[][3])
189 {
190  register int i, j, k;
191  for (i=0; i<3; ++i) {
192  for (j=0; j<3; ++j) {
193  A[i][j] = zero;
194  for (k=0; k<3; ++k) {
195  A[i][j] += B[i][k]*C[k][j];
196  }
197  }
198  }
199 }
200 
201 //......................................................................
203  const complex U[][3],
204  const complex Udagg[][3],
205  const double dmsqr[][3],
206  double L,
207  double E)
208 {
209  register int a, b, i;
210  for (a=0; a<3; ++a) {
211  for (b=0; b<3; ++b) {
212  A[a][b] = zero;
213  for (i=0; i<3; ++i) {
214  complex phase(0.0,-kK1*dmsqr[i][0]*L/E);
215  A[a][b] += U[a][i]*exp(phase)*Udagg[i][b];
216  }
217  }
218  }
219 }
220 
221 //......................................................................
222 void PMNS::EvalEqn5(complex twoEH[][3],
223  const complex U[][3],
224  const complex Udagg[][3],
225  const double dmsqr[][3],
226  double E,
227  double Gf,
228  double Ne)
229 {
230  register int j, k;
231  double k2r2GNeE = kK2*2.0*M_SQRT2*Gf*Ne*(kGeV2eV*E);
232  for (k=0; k<3; ++k) {
233  for (j=0; j<3; ++j) {
234  twoEH[k][j] = zero;
235  if (k==j) twoEH[k][j] = dmsqr[j][0];
236  twoEH[k][j] -= k2r2GNeE*U[0][j]*Udagg[k][0];
237  }
238  }
239 }
240 
241 //......................................................................
243  const complex U[][3],
244  const complex X[][3],
245  const complex Udagg[][3])
246 {
247  complex tmp[3][3];
248  this->Multi(tmp, X, Udagg);
249  this->Multi(A, U, tmp);
250 }
251 
252 //......................................................................
254  double L,
255  double E,
256  const complex twoEH[][3],
257  const double Msqr[],
258  const double dMsqr[][3])
259 {
260  // The identity matrix
261  static const double One[3][3] = {{1.,0.,0.},
262  {0.,1.,0.},
263  {0.,0.,1.}
264  };
265  register int a, b, k;
266  complex phase;
267  complex EHM0[3][3];
268  complex EHM1[3][3];
269  complex EHM2[3][3];
270  complex EHM21[3][3];
271  complex EHM20[3][3];
272  complex EHM10[3][3];
273 
274  // There are three matrices which can apper inside the product on
275  // j!=k. Calculate them before hand
276  for (a=0; a<3; ++a) {
277  for (b=0; b<3; ++b) {
278  EHM0[a][b] = twoEH[a][b]-Msqr[0]*One[a][b];
279  EHM1[a][b] = twoEH[a][b]-Msqr[1]*One[a][b];
280  EHM2[a][b] = twoEH[a][b]-Msqr[2]*One[a][b];
281  }
282  }
283  this->Multi(EHM21,EHM2,EHM1);
284  this->Multi(EHM20,EHM2,EHM0);
285  this->Multi(EHM10,EHM1,EHM0);
286 
287  // Refer to Msqr_j as dMsqr[j][0] since only mass differences matter
288  for (a=0; a<3; ++a) {
289  for (b=0; b<3; ++b) {
290  X[a][b] = zero;
291  for (k=0; k<3; ++k) {
292  phase = exp(complex(0.0,-kK1*dMsqr[k][0]*L/E));
293  if (k==0) {
294  X[a][b] += (EHM21[a][b]/(dMsqr[k][2]*dMsqr[k][1]))*phase;
295  }
296  else if (k==1) {
297  X[a][b] += (EHM20[a][b]/(dMsqr[k][2]*dMsqr[k][0]))*phase;
298  }
299  else if (k==2) {
300  X[a][b] += (EHM10[a][b]/(dMsqr[k][1]*dMsqr[k][0]))*phase;
301  } // Switch for product on j!=k
302  } // Sum on k
303  } // Loop on b
304  } // Loop on a
305 }
306 
307 //......................................................................
308 //
309 // Find the matter eigenvalues Msqr given the variables found in
310 // Eqn.22. This is Eqn.21 from Barger et. al.
311 //
312 void PMNS::EvalEqn21(double Msqr[],
313  double alpha,
314  double beta,
315  double gamma)
316 {
317  double arg; // Argument of the acos()
318  double theta0; // First of the three roots of acos()
319  double theta1; // Second of the three roots of acos()
320  double theta2; // Third of the three roots of acos()
321  double fac; // Factor in front of cos() terms
322  double constant; // Offset for all eigenvalues
323  static const double k2PiOver3 = 2.0*M_PI/3.0;
324  double alpha2 = alpha*alpha;
325  double alpha3 = alpha*alpha2;
326  double alpha2Minus3beta = alpha2-3.0*beta;
327 
328  arg =
329  (2.0*alpha3 - 9.0*alpha*beta + 27.0*gamma)/
330  (2.0*pow(alpha2Minus3beta,1.5));
331 
332  // Occasionally round off errors mean that arg wanders outside of
333  // its allowed range. If its way off (1 part per billion), stop the
334  // program. Otherwise, set it to its real value.
335  if (fabs(arg)>1.0) {
336  if (fabs(arg-1.0)>1.E-9) abort();
337  if (arg<-1.0) arg = -1.00;
338  if (arg>+1.0) arg = +1.00;
339  }
340 
341  // The three roots, find the first by computing the acos() the
342  // others are nearby
343  theta0 = acos(arg)/3.0;
344  theta1 = theta0-k2PiOver3;
345  theta2 = theta0+k2PiOver3;
346 
347  // The multiplier and offset
348  fac = -2.0*sqrt(alpha2Minus3beta)/3.0;
349  constant = -alpha/3.0; // The constant offset m1^2 is irrelevant
350 
351  // And the eigenvalues themselves
352  Msqr[0] = fac*cos(theta0) + constant;
353  Msqr[1] = fac*cos(theta1) + constant;
354  Msqr[2] = fac*cos(theta2) + constant;
355 }
356 
357 void PMNS::EvalEqn22(double& alpha,
358  double& beta,
359  double& gamma,
360  double E,
361  double Gf,
362  double Ne,
363  const double dmsqr[][3],
364  const complex U[][3])
365 {
366  // 2*sqrt(2)*Gf*Ne*E in units of eV^2
367  double k2r2EGNe = kK2*2.0*M_SQRT2*Gf*Ne*(kGeV2eV*E);
368 
369  alpha = k2r2EGNe + dmsqr[0][1] + dmsqr[0][2];
370 
371  beta =
372  dmsqr[0][1]*dmsqr[0][2] +
373  k2r2EGNe*(dmsqr[0][1]*(1.0-norm(U[0][1])) +
374  dmsqr[0][2]*(1.0-norm(U[0][2])));
375 
376  gamma = k2r2EGNe*dmsqr[0][1]*dmsqr[0][2]*norm(U[0][0]);
377 }
378 
379 //......................................................................
380 void PMNS::SortEigenvalues(double dMsqr[][3],
381  const double dmsqr[][3],
382  const double MsqrVac[],
383  double Msqr[])
384 {
385  int i, j, k;
386  double best, delta;
387  double MsqrTmp[3] = {-99.9E9,-99.9E9,-99.9E9};
388  int flg[3] = {0,0,0};
389 
390  // Attempt to figure out which of the eigenvalues match between
391  // dmsqr and MsqrVac
392  for (i=0; i<3; ++i) {
393  best = 1.E30;
394  k = -1;
395  for (j=0; j<3; ++j) {
396  delta = fabs(MsqrVac[i] - dmsqr[j][0]);
397  if (delta<best) { best = delta; k = j; }
398  }
399  if (best>1.E-9) abort();
400  if (k<0 || k>2) abort();
401  flg[k] = 1;
402  MsqrTmp[i] = Msqr[k];
403  }
404  // Check that each eigenvalue is used
405  for (i=0; i<3; ++i) if (flg[i]!=1) abort();
406 
407  for (i=0; i<3; ++i) {
408  Msqr[i] = MsqrTmp[i];
409  for (j=0; j<3; ++j) {
410  dMsqr[i][j] = (MsqrTmp[i] - MsqrTmp[j]);
411  }
412  }
413 }
414 
415 void PMNS::PropVacuum(double L, double E, int anti)
416 {
417  register int i, j;
418  complex A[3][3];
419  complex Aout[3][3];
420 
421  if (anti>0) this->EvalEqn2(A, fU, fUdagg, fdmsqr, L, E);
422  else if (anti<0) this->EvalEqn2(A, fUstar, fUtran, fdmsqr, L, E);
423  else abort();
424  this->Multi(Aout, A, fA);
425  for (i=0; i<3; ++i) {
426  for (j=0; j<3; ++j) {
427  fA[i][j] = Aout[i][j];
428  }
429  }
430 }
431 
432 void PMNS::PropMatter(double L, double E, double Ne, int anti)
433 {
434  static const double Gf = 1.166371E-5; // G_F in units of GeV^-2
435  register int i, j;
436  complex twoEH[3][3];
437  complex X[3][3];
438  double Msqr[3];
439  double MsqrV[3];
440  double dMsqr[3][3];
441  double alpha, beta, gamma;
442  double alpha0, beta0, gamma0;
443  complex A[3][3];
444  complex Aout[3][3];
445 
446  // Find the transition matrix. The series of steps are to:
447  if (anti>0) {
448  // [1] Find the matter Hamiltonian in the mass basis...
449  this->EvalEqn5(twoEH, fU, fUdagg, fdmsqr, E, Gf, Ne);
450 
451  // [2] Find the eigenvalues and sort them.
452  this->EvalEqn22(alpha, beta, gamma, E, Gf, Ne, fdmsqr, fU);
453  this->EvalEqn21(Msqr, alpha, beta, gamma);
454 
455  // Repeat the above, but for vacuum (Ne=0.0) to sort out the order
456  // of the eigenvalues
457  this->EvalEqn22(alpha0, beta0, gamma0, E, 0.0, 0.0, fdmsqr, fU);
458  this->EvalEqn21(MsqrV, alpha0, beta0, gamma0);
459  this->SortEigenvalues(dMsqr, fdmsqr, MsqrV, Msqr);
460 
461  // [3] Evaluate the transition matrix
462  this->EvalEqn11(X, L, E, twoEH, Msqr, dMsqr);
463  this->EvalEqn10(A, fU, X, fUdagg);
464  }
465  else if (anti<0) {
466  // As above, but make required substitutions for anti-neutrinos:
467  // Gf=>-Gf, U=>Ustar, U^dagger=>U^dagger^*=U^T
468  this->EvalEqn5(twoEH, fUstar, fUtran, fdmsqr, E, -Gf, Ne);
469  this->EvalEqn22(alpha, beta, gamma, E, -Gf, Ne, fdmsqr, fUstar);
470  this->EvalEqn21(Msqr, alpha, beta, gamma);
471  this->EvalEqn22(alpha0, beta0, gamma0, E, 0.0, 0.0, fdmsqr, fUstar);
472  this->EvalEqn21(MsqrV, alpha0, beta0, gamma0);
473  this->SortEigenvalues(dMsqr, fdmsqr, MsqrV, Msqr);
474  this->EvalEqn11(X, L, E, twoEH, Msqr, dMsqr);
475  this->EvalEqn10(A, fUstar, X, fUtran);
476  }
477  else abort();
478 
479  // [4] Apply the transition matrix to the matrix we started with...
480  this->Multi(Aout, A, fA);
481  for (i=0; i<3; ++i) {
482  for (j=0; j<3; ++j) {
483  fA[i][j] = Aout[i][j];
484  }
485  }
486 }
487 
488 //......................................................................
489 void PMNS::PropMatter(const std::list<double>& L,
490  double E,
491  const std::list<double>& Ne,
492  int anti)
493 {
494  if (L.size()!=Ne.size()) abort();
495  std::list<double>::const_iterator Li (L.begin());
496  std::list<double>::const_iterator Lend(L.end());
497  std::list<double>::const_iterator Ni (Ne.begin());
498  for (; Li!=Lend; ++Li, ++Ni) {
499  // For very low densities, use vacumm
500  static const double kRhoCutoff = 1.0E-6; // Ne in moles/cm^3
501  if (*Ni<kRhoCutoff) this->PropVacuum(*Li, E, anti);
502  else this->PropMatter(*Li, E, *Ni, anti);
503  }
504 }
505 
506 //......................................................................
507 void PMNS::Reset()
508 {
509  register int i, j;
510  for (i=0; i<3; ++i) {
511  for (j=0; j<3; ++j) {
512  if (i==j) fA[i][j] = one;
513  else fA[i][j] = zero;
514  }
515  }
516 }
517 
518 //......................................................................
519 double PMNS::P(int i, int j) const
520 {
521  assert(i>=0 && i<3);
522  assert(j>=0 && j<3);
523  return norm(fA[i][j]);
524 }
525 
void PrintMix() const
Definition: PMNS.cxx:82
PMNS()
Definition: PMNS.cxx:52
void EvalEqn2(complex A[][3], const complex U[][3], const complex Udagg[][3], const double dmsqr[][3], double L, double E)
Definition: PMNS.cxx:202
complex fU[3][3]
Definition: PMNS.h:127
void EvalEqn21(double Msqr[], double alpha, double beta, double gamma)
Definition: PMNS.cxx:312
void SetMixBWCP(double th1, double th2, double th3, double deltacp)
Definition: PMNS.cxx:117
void PrintDeltaMsqrs() const
Definition: PMNS.cxx:149
void DumpMatrix(const complex M[][3]) const
Definition: PMNS.cxx:71
constexpr T pow(T x)
Definition: pow.h:72
static std::complex< double > zero(0.0, 0.0)
intermediate_table::const_iterator const_iterator
complex fUdagg[3][3]
Definition: PMNS.h:128
complex fUstar[3][3]
Definition: PMNS.h:129
void PropMatter(double L, double E, double Ne, int anti)
Definition: PMNS.cxx:432
complex fUtran[3][3]
Definition: PMNS.h:130
static const double kK2
Definition: PMNS.cxx:47
static std::complex< double > one(1.0, 0.0)
string tmp
Definition: languages.py:63
Definition: EarthModel.h:12
auto norm(Vector const &v)
Return norm of the specified vector.
void SetDeltaMsqrs(double dm21, double dm32)
Definition: PMNS.cxx:159
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
void EvalEqn5(complex twoEH[][3], const complex U[][3], const complex Udagg[][3], const double dmsqr[][3], double E, double Gf, double Ne)
Definition: PMNS.cxx:222
void SetMix(double th12, double th23, double th13, double deltacp)
Definition: PMNS.cxx:86
std::complex< double > complex
Definition: PMNS.h:73
void EvalEqn11(complex X[][3], double L, double E, const complex twoEH[][3], const double Msqr[], const double dMsqr[][3])
Definition: PMNS.cxx:253
void SortEigenvalues(double dMsqr[][3], const double dmsqr[][3], const double MsqrVac[], double Msqr[])
Definition: PMNS.cxx:380
E
Definition: 018_def.c:13
static const double kGeV2eV
Definition: PMNS.cxx:48
void EvalEqn22(double &alpha, double &beta, double &gamma, double E, double Gf, double Ne, const double dmsqr[][3], const complex U[][3])
Definition: PMNS.cxx:357
#define A
Definition: memgrp.cpp:38
static bool * b
Definition: config.cpp:1043
double fdmsqr[3][3]
Definition: PMNS.h:126
void PropVacuum(double L, double E, int anti)
Definition: PMNS.cxx:415
double P(int i, int j) const
Definition: PMNS.cxx:519
void EvalEqn10(complex A[][3], const complex U[][3], const complex X[][3], const complex Udagg[][3])
Definition: PMNS.cxx:242
static const double kK1
Definition: PMNS.cxx:46
void Reset()
Definition: PMNS.cxx:507
void Multi(complex A[][3], const complex B[][3], const complex C[][3])
Definition: PMNS.cxx:188
QTextStream & endl(QTextStream &s)
complex fA[3][3]
Definition: PMNS.h:131