OscProb
PMNS_Base.cxx
Go to the documentation of this file.
1
2//
3// Base class for oscillations of neutrinos in matter in a
4// n-neutrino framework.
5//
6//.............................................................................
7//
8// jcoelho\@apc.in2p3.fr
9//
11
12#include "PMNS_Base.h"
13#include <algorithm>
14#include <cassert>
15#include <iostream>
16
17using namespace std;
18
19using namespace OscProb;
20
21// Some usefule complex numbers
22const complexD PMNS_Base::zero(0, 0);
23const complexD PMNS_Base::one(1, 0);
24
25// Define some constants from PDG 2015
26const double PMNS_Base::kGeV2eV = 1.0e+09; // GeV to eV conversion
27const double PMNS_Base::kKm2eV = 1.0 / 1.973269788e-10; // (hbar.c [eV.km])^-1
28const double PMNS_Base::kNA = 6.022140857e23; // Avogadro constant (N_A)
29const double PMNS_Base::kK2 =
30 1e-3 * kNA / pow(kKm2eV, 3); // N_A * (hbar*c [GeV.cm])^3 * kGeV2eV
31const double PMNS_Base::kGf = 1.1663787e-05; // G_F/(hbar*c)^3 [GeV^-2]
32
33//.............................................................................
47PMNS_Base::PMNS_Base(int numNus)
48 : fGotES(false), fBuiltHms(false), fMaxCache(1e6), fProbe(numNus)
49{
50 SetUseCache(true); // Cache eigensystems
51
52 fNumNus = numNus; // Set the number of neutrinos
53
54 SetStdPath(); // Set some default path
55 SetEnergy(2); // Set default energy to 2 GeV
56 SetIsNuBar(false); // Neutrino by default
57
58 InitializeVectors(); // Initialize all vectors
59
60 SetStdPars(); // Set PDG parameters
61
62 ResetToFlavour(1); // Numu by default
63
64 ClearCache(); // Clear cache to initialize it
65
66 SetAvgProbPrec(1e-4); // Set default AvgProb precision
67}
68
69//.............................................................................
74
75//.............................................................................
81 fDm = vectorD(fNumNus, 0);
84
87
90
91 fEval = vectorD(fNumNus, 0);
93}
94
95//.............................................................................
106
107//.............................................................................
112{
113 fMixCache.clear();
114
115 // Set some better hash table parameters
116 fMixCache.max_load_factor(0.25);
117 fMixCache.reserve(512);
118}
119
120//.............................................................................
128void PMNS_Base::SetMaxCache(int mc) { fMaxCache = mc; }
129
130//.............................................................................
135{
136 if (fUseCache && !fMixCache.empty()) {
138
139 unordered_set<EigenPoint>::iterator it = fMixCache.find(fProbe);
140
141 if (it != fMixCache.end()) {
142 for (int i = 0; i < fNumNus; i++) {
143 fEval[i] = (*it).fEval[i] * (*it).fEnergy / fEnergy;
144 for (int j = 0; j < fNumNus; j++) { fEvec[i][j] = (*it).fEvec[i][j]; }
145 }
146 return true;
147 }
148 }
149
150 return false;
151}
152
153//.............................................................................
158{
159 if (fUseCache) {
160 if (fMixCache.size() > fMaxCache) { fMixCache.erase(fMixCache.begin()); }
162 for (int i = 0; i < fNumNus; i++) {
163 fProbe.fEval[i] = fEval[i];
164 for (int j = 0; j < fNumNus; j++) { fProbe.fEvec[i][j] = fEvec[i][j]; }
165 }
166 fMixCache.insert(fProbe);
167 }
168}
169
170//.............................................................................
178{
179 if (fNumNus > 2) {
180 // PDG values for 3 neutrinos
181 // Also applicable for 3+N neutrinos
182 SetAngle(1, 2, asin(sqrt(0.304)));
183 SetAngle(1, 3, asin(sqrt(0.0219)));
184 SetAngle(2, 3, asin(sqrt(0.514)));
185 SetDm(2, 7.53e-5);
186 SetDm(3, 2.52e-3);
187 }
188 else if (fNumNus == 2) {
189 // Effective muon disappearance values
190 // for two-flavour approximation
191 SetAngle(1, 2, 0.788);
192 SetDm(2, 2.47e-3);
193 }
194}
195
196//.............................................................................
206{
207 NuPath p;
208
209 p.length = 1000; // 1000 km default
210 p.density = 2.8; // Crust density
211 p.zoa = 0.5; // Crust Z/A
212 p.layer = 0; // Single layer
213
214 SetPath(p);
215}
216
217//.............................................................................
227{
228 // Check if value is actually changing
229 fGotES *= (fEnergy == E);
230
231 fEnergy = E;
232}
233
234//.............................................................................
243void PMNS_Base::SetIsNuBar(bool isNuBar)
244{
245 // Check if value is actually changing
246 fGotES *= (fIsNuBar == isNuBar);
247
248 fIsNuBar = isNuBar;
249}
250
251//.............................................................................
255double PMNS_Base::GetEnergy() { return fEnergy; }
256
257//.............................................................................
262
263//.............................................................................
275{
276 // Check if relevant value are actually changing
277 fGotES *= (fPath.density == p.density);
278 fGotES *= (fPath.zoa == p.zoa);
279
280 fPath = p;
281}
282
283//.............................................................................
288
289//.............................................................................
294void PMNS_Base::SetPath(std::vector<NuPath> paths) { fNuPaths = paths; }
295
296//.............................................................................
300vector<NuPath> PMNS_Base::GetPath() { return fNuPaths; }
301
302//.............................................................................
307void PMNS_Base::AddPath(NuPath p) { fNuPaths.push_back(p); }
308
309//.............................................................................
317void PMNS_Base::AddPath(double length, double density, double zoa, int layer)
318{
319 AddPath(NuPath(length, density, zoa, layer));
320}
321
322//.............................................................................
331{
332 ClearPath();
333 AddPath(p);
334}
335
336//.............................................................................
347void PMNS_Base::SetPath(double length, double density, double zoa, int layer)
348{
349 SetPath(NuPath(length, density, zoa, layer));
350}
351
352//.............................................................................
364void PMNS_Base::SetAtt(double att, int idx)
365{
366 if (fNuPaths.size() != 1) {
367 cerr << "WARNING: Clearing path vector and starting new single path."
368 << endl
369 << "To avoid possible issues, use the SetPath function." << endl;
370
371 SetStdPath();
372 }
373
374 switch (idx) {
375 case 0: fNuPaths[0].length = att; break;
376 case 1: fNuPaths[0].density = att; break;
377 case 2: fNuPaths[0].zoa = att; break;
378 case 3: fNuPaths[0].layer = att; break;
379 }
380}
381
382//.............................................................................
391void PMNS_Base::SetLength(double L) { SetAtt(L, 0); }
392
393//.............................................................................
402void PMNS_Base::SetDensity(double rho) { SetAtt(rho, 1); }
403
404//.............................................................................
413void PMNS_Base::SetZoA(double zoa) { SetAtt(zoa, 2); }
414
415//.............................................................................
427void PMNS_Base::SetAtt(vectorD att, int idx)
428{
429 // Get the sizes of the attribute and
430 // path sequence vectors
431 int nA = att.size();
432 int nP = fNuPaths.size();
433
434 // If the vector sizes are equal, update this attribute
435 if (nA == nP) {
436 for (int i = 0; i < nP; i++) {
437 switch (idx) {
438 case 0: fNuPaths[i].length = att[i]; break;
439 case 1: fNuPaths[i].density = att[i]; break;
440 case 2: fNuPaths[i].zoa = att[i]; break;
441 case 3: fNuPaths[i].layer = att[i]; break;
442 }
443 }
444 }
445 // If the vector sizes differ, create a new path sequence
446 // and set value for this attribute. Other attributes will
447 // be taken from default single path.
448 else {
449 cerr << "WARNING: New vector size. Starting new path vector." << endl
450 << "To avoid possible issues, use the SetPath function." << endl;
451
452 // Start a new standard path just
453 // to set default values
454 SetStdPath();
455
456 // Create a path segment with default values
457 NuPath p = fNuPaths[0];
458
459 // Clear the path sequence
460 ClearPath();
461
462 // Set this particular attribute's value
463 // and add the path segment to the sequence
464 for (int i = 0; i < nA; i++) {
465 switch (idx) {
466 case 0: p.length = att[i]; break;
467 case 1: p.density = att[i]; break;
468 case 2: p.zoa = att[i]; break;
469 case 3: p.layer = att[i]; break;
470 }
471
472 AddPath(p);
473 }
474 }
475}
476
477//.............................................................................
487
488//.............................................................................
498
499//.............................................................................
508void PMNS_Base::SetZoA(vectorD zoa) { SetAtt(zoa, 2); }
509
510//.............................................................................
520{
521 vectorD lay_double(lay.begin(), lay.end());
522
523 SetAtt(lay_double, 3);
524}
525
526//.............................................................................
539void PMNS_Base::SetAngle(int i, int j, double th)
540{
541 if (i > j) {
542 cerr << "WARNING: First argument should be smaller than second argument"
543 << endl
544 << " Setting reverse order (Theta" << j << i << "). " << endl;
545 int temp = i;
546 i = j;
547 j = temp;
548 }
549 if (i < 1 || i > fNumNus - 1 || j < 2 || j > fNumNus) {
550 cerr << "ERROR: Theta" << i << j << " not valid for " << fNumNus
551 << " neutrinos. Doing nothing." << endl;
552 return;
553 }
554
555 // Check if value is actually changing
556 fBuiltHms *= (fTheta[i - 1][j - 1] == th);
557
558 fTheta[i - 1][j - 1] = th;
559}
560
561//.............................................................................
570double PMNS_Base::GetAngle(int i, int j)
571{
572 if (i > j) {
573 cerr << "WARNING: First argument should be smaller than second argument"
574 << endl
575 << " Setting reverse order (Theta" << j << i << "). " << endl;
576 int temp = i;
577 i = j;
578 j = temp;
579 }
580 if (i < 1 || i > fNumNus - 1 || j < 2 || j > fNumNus) {
581 cerr << "ERROR: Theta" << i << j << " not valid for " << fNumNus
582 << " neutrinos. Returning zero." << endl;
583 return 0;
584 }
585
586 return fTheta[i - 1][j - 1];
587}
588
589//.............................................................................
602void PMNS_Base::SetDelta(int i, int j, double delta)
603{
604 if (i > j) {
605 cerr << "WARNING: First argument should be smaller than second argument"
606 << endl
607 << " Setting reverse order (Delta" << j << i << "). " << endl;
608 int temp = i;
609 i = j;
610 j = temp;
611 }
612 if (i < 1 || i > fNumNus - 1 || j < 2 || j > fNumNus) {
613 cerr << "ERROR: Delta" << i << j << " not valid for " << fNumNus
614 << " neutrinos. Doing nothing." << endl;
615 return;
616 }
617 if (i + 1 == j) {
618 cerr << "WARNING: Rotation " << i << j << " is real. Doing nothing."
619 << endl;
620 return;
621 }
622
623 // Check if value is actually changing
624 fBuiltHms *= (fDelta[i - 1][j - 1] == delta);
625
626 fDelta[i - 1][j - 1] = delta;
627}
628
629//.............................................................................
638double PMNS_Base::GetDelta(int i, int j)
639{
640 if (i > j) {
641 cerr << "WARNING: First argument should be smaller than second argument"
642 << endl
643 << " Setting reverse order (Delta" << j << i << "). " << endl;
644 int temp = i;
645 i = j;
646 j = temp;
647 }
648 if (i < 1 || i > fNumNus - 1 || j < 2 || j > fNumNus) {
649 cerr << "ERROR: Delta" << i << j << " not valid for " << fNumNus
650 << " neutrinos. Returning zero." << endl;
651 return 0;
652 }
653 if (i + 1 == j) {
654 cerr << "WARNING: Rotation " << i << j << " is real. Returning zero."
655 << endl;
656 return 0;
657 }
658
659 return fDelta[i - 1][j - 1];
660}
661
662//.............................................................................
674void PMNS_Base::SetDm(int j, double dm)
675{
676 if (j < 2 || j > fNumNus) {
677 cerr << "ERROR: Dm" << j << "1 not valid for " << fNumNus
678 << " neutrinos. Doing nothing." << endl;
679 return;
680 }
681
682 // Check if value is actually changing
683 fBuiltHms *= (fDm[j - 1] == dm);
684
685 fDm[j - 1] = dm;
686}
687
688//.............................................................................
696double PMNS_Base::GetDm(int j)
697{
698 if (j < 2 || j > fNumNus) {
699 cerr << "ERROR: Dm" << j << "1 not valid for " << fNumNus
700 << " neutrinos. Returning zero." << endl;
701 return 0;
702 }
703
704 return fDm[j - 1];
705}
706
707//.............................................................................
716{
717 vectorI idx(x.size(), 0);
718 for (int i = 0; i < x.size(); i++) idx[i] = i;
719 sort(idx.begin(), idx.end(), IdxCompare(x));
720
721 return idx;
722}
723
724//.............................................................................
733{
734 if (j < 2 || j > fNumNus) {
735 cerr << "ERROR: Dm_" << j << "1 not valid for " << fNumNus
736 << " neutrinos. Returning zero." << endl;
737 return 0;
738 }
739
740 // Solve the Hamiltonian to update eigenvalues
741 SolveHam();
742
743 // Sort eigenvalues in same order as vacuum Dm^2
744 vectorI dm_idx = GetSortedIndices(fDm);
745 vectorD dm_idx_double(dm_idx.begin(), dm_idx.end());
746 dm_idx = GetSortedIndices(dm_idx_double);
748
749 // Return difference in eigenvalues * 2E
750 return (fEval[ev_idx[dm_idx[j - 1]]] - fEval[ev_idx[dm_idx[0]]]) * 2 *
752}
753
754//.............................................................................
760void PMNS_Base::RotateState(int i, int j)
761{
762 // Do nothing if angle is zero
763 if (fTheta[i][j] == 0) return;
764
765 double sij = sin(fTheta[i][j]);
766 double cij = cos(fTheta[i][j]);
767
768 complexD buffer;
769
770 if (i + 1 == j || fDelta[i][j] == 0) {
771 buffer = cij * fNuState[i] + sij * fNuState[j];
772 fNuState[j] = cij * fNuState[j] - sij * fNuState[i];
773 }
774 else {
775 complexD eij = complexD(cos(fDelta[i][j]), -sin(fDelta[i][j]));
776 buffer = cij * fNuState[i] + sij * eij * fNuState[j];
777 fNuState[j] = cij * fNuState[j] - sij * conj(eij) * fNuState[i];
778 }
779
780 fNuState[i] = buffer;
781}
782
783//.............................................................................
796{
797 vectorC oldState = fNuState;
798
799 ResetToFlavour(mi);
800
801 for (int j = 0; j < fNumNus; j++) {
802 for (int i = 0; i < j; i++) { RotateState(i, j); }
803 }
804
805 vectorC newState = fNuState;
806 fNuState = oldState;
807
808 return newState;
809}
810
811//.............................................................................
822void PMNS_Base::RotateH(int i, int j, matrixC& Ham)
823{
824 // Do nothing if angle is zero
825 if (fTheta[i][j] == 0) return;
826
827 double fSinBuffer = sin(fTheta[i][j]);
828 double fCosBuffer = cos(fTheta[i][j]);
829
830 double fHmsBufferD;
831 complexD fHmsBufferC;
832
833 // With Delta
834 if (i + 1 < j) {
835 complexD fExpBuffer = complexD(cos(fDelta[i][j]), -sin(fDelta[i][j]));
836
837 // General case
838 if (i > 0) {
839 // Top columns
840 for (int k = 0; k < i; k++) {
841 fHmsBufferC = Ham[k][i];
842
843 Ham[k][i] *= fCosBuffer;
844 Ham[k][i] += Ham[k][j] * fSinBuffer * conj(fExpBuffer);
845
846 Ham[k][j] *= fCosBuffer;
847 Ham[k][j] -= fHmsBufferC * fSinBuffer * fExpBuffer;
848 }
849
850 // Middle row and column
851 for (int k = i + 1; k < j; k++) {
852 fHmsBufferC = Ham[k][j];
853
854 Ham[k][j] *= fCosBuffer;
855 Ham[k][j] -= conj(Ham[i][k]) * fSinBuffer * fExpBuffer;
856
857 Ham[i][k] *= fCosBuffer;
858 Ham[i][k] += fSinBuffer * fExpBuffer * conj(fHmsBufferC);
859 }
860
861 // Nodes ij
862 fHmsBufferC = Ham[i][i];
863 fHmsBufferD = real(Ham[j][j]);
864
865 Ham[i][i] *= fCosBuffer * fCosBuffer;
866 Ham[i][i] +=
867 2 * fSinBuffer * fCosBuffer * real(Ham[i][j] * conj(fExpBuffer));
868 Ham[i][i] += fSinBuffer * Ham[j][j] * fSinBuffer;
869
870 Ham[j][j] *= fCosBuffer * fCosBuffer;
871 Ham[j][j] += fSinBuffer * fHmsBufferC * fSinBuffer;
872 Ham[j][j] -=
873 2 * fSinBuffer * fCosBuffer * real(Ham[i][j] * conj(fExpBuffer));
874
875 Ham[i][j] -= 2 * fSinBuffer * real(Ham[i][j] * conj(fExpBuffer)) *
876 fSinBuffer * fExpBuffer;
877 Ham[i][j] +=
878 fSinBuffer * fCosBuffer * (fHmsBufferD - fHmsBufferC) * fExpBuffer;
879 }
880 // First rotation on j (No top columns)
881 else {
882 // Middle rows and columns
883 for (int k = i + 1; k < j; k++) {
884 Ham[k][j] = -conj(Ham[i][k]) * fSinBuffer * fExpBuffer;
885
886 Ham[i][k] *= fCosBuffer;
887 }
888
889 // Nodes ij
890 fHmsBufferD = real(Ham[i][i]);
891
892 Ham[i][j] =
893 fSinBuffer * fCosBuffer * (Ham[j][j] - fHmsBufferD) * fExpBuffer;
894
895 Ham[i][i] *= fCosBuffer * fCosBuffer;
896 Ham[i][i] += fSinBuffer * Ham[j][j] * fSinBuffer;
897
898 Ham[j][j] *= fCosBuffer * fCosBuffer;
899 Ham[j][j] += fSinBuffer * fHmsBufferD * fSinBuffer;
900 }
901 }
902 // Without Delta (No middle rows or columns: j = i+1)
903 else {
904 // General case
905 if (i > 0) {
906 // Top columns
907 for (int k = 0; k < i; k++) {
908 fHmsBufferC = Ham[k][i];
909
910 Ham[k][i] *= fCosBuffer;
911 Ham[k][i] += Ham[k][j] * fSinBuffer;
912
913 Ham[k][j] *= fCosBuffer;
914 Ham[k][j] -= fHmsBufferC * fSinBuffer;
915 }
916
917 // Nodes ij
918 fHmsBufferC = Ham[i][i];
919 fHmsBufferD = real(Ham[j][j]);
920
921 Ham[i][i] *= fCosBuffer * fCosBuffer;
922 Ham[i][i] += 2 * fSinBuffer * fCosBuffer * real(Ham[i][j]);
923 Ham[i][i] += fSinBuffer * Ham[j][j] * fSinBuffer;
924
925 Ham[j][j] *= fCosBuffer * fCosBuffer;
926 Ham[j][j] += fSinBuffer * fHmsBufferC * fSinBuffer;
927 Ham[j][j] -= 2 * fSinBuffer * fCosBuffer * real(Ham[i][j]);
928
929 Ham[i][j] -= 2 * fSinBuffer * real(Ham[i][j]) * fSinBuffer;
930 Ham[i][j] += fSinBuffer * fCosBuffer * (fHmsBufferD - fHmsBufferC);
931 }
932 // First rotation (theta12)
933 else {
934 Ham[i][j] = fSinBuffer * fCosBuffer * Ham[j][j];
935
936 Ham[i][i] = fSinBuffer * Ham[j][j] * fSinBuffer;
937
938 Ham[j][j] *= fCosBuffer * fCosBuffer;
939 }
940 }
941}
942
943//.............................................................................
956{
957 // Check if anything changed
958 if (fBuiltHms) return;
959
960 // Tag to recompute eigensystem
961 fGotES = false;
962
963 for (int j = 0; j < fNumNus; j++) {
964 // Set mass splitting
965 fHms[j][j] = fDm[j];
966 // Reset off-diagonal elements
967 for (int i = 0; i < j; i++) { fHms[i][j] = 0; }
968 // Rotate j neutrinos
969 for (int i = 0; i < j; i++) { RotateH(i, j, fHms); }
970 }
971
972 ClearCache();
973
974 // Tag as built
975 fBuiltHms = true;
976}
977
978//.............................................................................
984{
985 // Set the neutrino path
986 SetCurPath(p);
987
988 // Solve for eigensystem
989 SolveHam();
990
991 double LengthIneV = kKm2eV * p.length;
992 for (int i = 0; i < fNumNus; i++) {
993 double arg = fEval[i] * LengthIneV;
994 fPhases[i] = complexD(cos(arg), -sin(arg));
995 }
996
997 for (int i = 0; i < fNumNus; i++) {
998 fBuffer[i] = 0;
999 for (int j = 0; j < fNumNus; j++) {
1000 fBuffer[i] += conj(fEvec[j][i]) * fNuState[j];
1001 }
1002 fBuffer[i] *= fPhases[i];
1003 }
1004
1005 // Propagate neutrino state
1006 for (int i = 0; i < fNumNus; i++) {
1007 fNuState[i] = 0;
1008 for (int j = 0; j < fNumNus; j++) {
1009 fNuState[i] += fEvec[i][j] * fBuffer[j];
1010 }
1011 }
1012}
1013
1014//.............................................................................
1019{
1020 for (int i = 0; i < int(fNuPaths.size()); i++) { PropagatePath(fNuPaths[i]); }
1021}
1022
1023//.............................................................................
1035{
1036 assert(flv >= 0 && flv < fNumNus);
1037 for (int i = 0; i < fNumNus; ++i) {
1038 if (i == flv)
1039 fNuState[i] = one;
1040 else
1041 fNuState[i] = zero;
1042 }
1043}
1044
1045//.............................................................................
1058double PMNS_Base::P(int flv)
1059{
1060 assert(flv >= 0 && flv < fNumNus);
1061 return norm(fNuState[flv]);
1062}
1063
1064//.............................................................................
1071{
1072 assert(nu_in.size() == fNumNus);
1073
1074 fNuState = nu_in;
1075}
1076
1077//.............................................................................
1091double PMNS_Base::Prob(int flvi, int flvf)
1092{
1093 ResetToFlavour(flvi);
1094
1095 Propagate();
1096
1097 return P(flvf);
1098}
1099
1100//.............................................................................
1114double PMNS_Base::Prob(vectorC nu_in, int flvf)
1115{
1116 SetPureState(nu_in);
1117
1118 Propagate();
1119
1120 return P(flvf);
1121}
1122
1123//.............................................................................
1138double PMNS_Base::Prob(vectorC nu_in, int flvf, double E)
1139{
1140 SetEnergy(E);
1141
1142 return Prob(nu_in, flvf);
1143}
1144
1145//.............................................................................
1160double PMNS_Base::Prob(int flvi, int flvf, double E)
1161{
1162 SetEnergy(E);
1163
1164 return Prob(flvi, flvf);
1165}
1166
1167//.............................................................................
1189double PMNS_Base::Prob(vectorC nu_in, int flvf, double E, double L)
1190{
1191 SetEnergy(E);
1192 SetLength(L);
1193
1194 return Prob(nu_in, flvf);
1195}
1196
1197//.............................................................................
1219double PMNS_Base::Prob(int flvi, int flvf, double E, double L)
1220{
1221 SetEnergy(E);
1222 SetLength(L);
1223
1224 return Prob(flvi, flvf);
1225}
1226
1227//.............................................................................
1234{
1235 vectorD probs(fNumNus);
1236
1237 for (int i = 0; i < probs.size(); i++) { probs[i] = P(i); }
1238
1239 return probs;
1240}
1241
1242//.............................................................................
1251{
1252 SetPureState(nu_in);
1253
1254 Propagate();
1255
1256 return GetProbVector();
1257}
1258
1259//.............................................................................
1273{
1274 ResetToFlavour(flvi);
1275
1276 Propagate();
1277
1278 return GetProbVector();
1279}
1280
1281//.............................................................................
1292{
1293 SetEnergy(E);
1294
1295 return ProbVector(nu_in);
1296}
1297
1298//.............................................................................
1314{
1315 SetEnergy(E);
1316
1317 return ProbVector(flvi);
1318}
1319
1320//.............................................................................
1336vectorD PMNS_Base::ProbVector(vectorC nu_in, double E, double L)
1337{
1338 SetEnergy(E);
1339 SetLength(L);
1340
1341 return ProbVector(nu_in);
1342}
1343
1344//.............................................................................
1365vectorD PMNS_Base::ProbVector(int flvi, double E, double L)
1366{
1367 SetEnergy(E);
1368 SetLength(L);
1369
1370 return ProbVector(flvi);
1371}
1372
1373//.............................................................................
1387matrixD PMNS_Base::ProbMatrix(int nflvi, int nflvf)
1388{
1389 assert(nflvi <= fNumNus && nflvi >= 0);
1390 assert(nflvf <= fNumNus && nflvf >= 0);
1391
1392 // Output probabilities
1393 matrixD probs(nflvi, vectorD(nflvf));
1394
1395 // List of states
1396 matrixC allstates(nflvi, vectorC(fNumNus));
1397
1398 // Reset all initial states
1399 for (int i = 0; i < nflvi; i++) {
1400 ResetToFlavour(i);
1401 allstates[i] = fNuState;
1402 }
1403
1404 // Propagate all states in parallel
1405 for (int i = 0; i < int(fNuPaths.size()); i++) {
1406 for (int flvi = 0; flvi < nflvi; flvi++) {
1407 fNuState = allstates[flvi];
1409 allstates[flvi] = fNuState;
1410 }
1411 }
1412
1413 // Get all probabilities
1414 for (int flvi = 0; flvi < nflvi; flvi++) {
1415 for (int flvj = 0; flvj < nflvf; flvj++) {
1416 probs[flvi][flvj] = norm(allstates[flvi][flvj]);
1417 }
1418 }
1419
1420 return probs;
1421}
1422
1423//.............................................................................
1439matrixD PMNS_Base::ProbMatrix(int nflvi, int nflvf, double E)
1440{
1441 SetEnergy(E);
1442
1443 return ProbMatrix(nflvi, nflvf);
1444}
1445
1446//.............................................................................
1468matrixD PMNS_Base::ProbMatrix(int nflvi, int nflvf, double E, double L)
1469{
1470 SetEnergy(E);
1471 SetLength(L);
1472
1473 return ProbMatrix(nflvi, nflvf);
1474}
1475
1476//.............................................................................
1500double PMNS_Base::AvgProb(int flvi, int flvf, double E, double dE)
1501{
1502 ResetToFlavour(flvi);
1503
1504 return AvgProb(fNuState, flvf, E, dE);
1505}
1506
1507//.............................................................................
1517{
1518 // Make sure fPath is set
1519 // Use average if multiple paths
1521
1522 // Define L/E variables
1523 vectorD LoEbin(2);
1524
1525 // Set a minimum energy
1526 double minE = 0.1 * E;
1527
1528 // Transform range to L/E
1529 // Full range if low edge > minE
1530 if (E - dE / 2 > minE) {
1531 LoEbin[0] =
1532 0.5 * (fPath.length / (E - dE / 2) + fPath.length / (E + dE / 2));
1533 LoEbin[1] = fPath.length / (E - dE / 2) - fPath.length / (E + dE / 2);
1534 }
1535 // Else start at minE
1536 else {
1537 LoEbin[0] = 0.5 * (fPath.length / minE + fPath.length / (E + dE / 2));
1538 LoEbin[1] = fPath.length / minE - fPath.length / (E + dE / 2);
1539 }
1540
1541 return LoEbin;
1542}
1543
1544//.............................................................................
1568double PMNS_Base::AvgProb(vectorC nu_in, int flvf, double E, double dE)
1569{
1570 // Do nothing if energy is not positive
1571 if (E <= 0) return 0;
1572
1573 if (fNuPaths.empty()) return 0;
1574
1575 // Don't average zero width
1576 if (dE <= 0) return Prob(nu_in, flvf, E);
1577
1578 vectorD LoEbin = ConvertEtoLoE(E, dE);
1579
1580 // Compute average in LoE
1581 return AvgProbLoE(nu_in, flvf, LoEbin[0], LoEbin[1]);
1582}
1583
1584//.............................................................................
1610double PMNS_Base::AvgProbLoE(int flvi, int flvf, double LoE, double dLoE)
1611{
1612 ResetToFlavour(flvi);
1613
1614 return AvgProbLoE(fNuState, flvf, LoE, dLoE);
1615}
1616
1617//.............................................................................
1643double PMNS_Base::AvgProbLoE(vectorC nu_in, int flvf, double LoE, double dLoE)
1644{
1645 // Do nothing if L/E is not positive
1646 if (LoE <= 0) return 0;
1647
1648 if (fNuPaths.empty()) return 0;
1649
1650 // Make sure fPath is set
1651 // Use average if multiple paths
1653
1654 // Set the energy at bin center
1655 SetEnergy(fPath.length / LoE);
1656
1657 // Don't average zero width
1658 if (dLoE <= 0) return Prob(nu_in, flvf);
1659
1660 // Get sample points for this bin
1661 vectorD samples = GetSamplePoints(LoE, dLoE);
1662
1663 // Variables to fill sample
1664 // probabilities and weights
1665 double sumw = 0;
1666 double prob = 0;
1667 double length = fPath.length;
1668
1669 // Loop over all sample points
1670 for (int j = 0; j < int(samples.size()); j++) {
1671 // Set (L/E)^-2 weights
1672 double w = 1. / pow(samples[j], 2);
1673
1674 // Add weighted probability
1675 prob += w * Prob(nu_in, flvf, length / samples[j]);
1676
1677 // Increment sum of weights
1678 sumw += w;
1679 }
1680
1681 // Return weighted average of probabilities
1682 return prob / sumw;
1683}
1684
1685//.............................................................................
1705vectorD PMNS_Base::AvgProbVectorLoE(int flvi, double LoE, double dLoE)
1706{
1707 ResetToFlavour(flvi);
1708 return AvgProbVectorLoE(fNuState, LoE, dLoE);
1709}
1710
1711//.............................................................................
1729vectorD PMNS_Base::AvgProbVector(int flvi, double E, double dE)
1730{
1731 ResetToFlavour(flvi);
1732 return AvgProbVector(fNuState, E, dE);
1733}
1734
1735//.............................................................................
1753vectorD PMNS_Base::AvgProbVector(vectorC nu_in, double E, double dE)
1754{
1755 vectorD probs(fNumNus, 0);
1756
1757 // Do nothing if energy is not positive
1758 if (E <= 0) return probs;
1759
1760 if (fNuPaths.empty()) return probs;
1761
1762 // Don't average zero width
1763 if (dE <= 0) return ProbVector(nu_in, E);
1764
1765 vectorD LoEbin = ConvertEtoLoE(E, dE);
1766
1767 // Compute average in LoE
1768 return AvgProbVectorLoE(nu_in, LoEbin[0], LoEbin[1]);
1769}
1770
1771//.............................................................................
1791vectorD PMNS_Base::AvgProbVectorLoE(vectorC nu_in, double LoE, double dLoE)
1792{
1793 vectorD probs(fNumNus, 0);
1794
1795 // Do nothing if L/E is not positive
1796 if (LoE <= 0) return probs;
1797
1798 if (fNuPaths.empty()) return probs;
1799
1800 // Make sure fPath is set
1801 // Use average if multiple paths
1803
1804 // Set the energy at bin center
1805 SetEnergy(fPath.length / LoE);
1806
1807 // Don't average zero width
1808 if (dLoE <= 0) return ProbVector(nu_in);
1809
1810 // Get sample points for this bin
1811 vectorD samples = GetSamplePoints(LoE, dLoE);
1812
1813 // Variables to fill sample
1814 // probabilities and weights
1815 double sumw = 0;
1816 double length = fPath.length;
1817
1818 // Loop over all sample points
1819 for (int j = 0; j < int(samples.size()); j++) {
1820 // Set (L/E)^-2 weights
1821 double w = 1. / pow(samples[j], 2);
1822
1823 vectorD sample_probs = ProbVector(nu_in, length / samples[j]);
1824
1825 for (int i = 0; i < fNumNus; i++) {
1826 // Add weighted probability
1827 probs[i] += w * sample_probs[i];
1828 }
1829 // Increment sum of weights
1830 sumw += w;
1831 }
1832
1833 for (int i = 0; i < fNumNus; i++) {
1834 // Divide by total sampling weight
1835 probs[i] /= sumw;
1836 }
1837
1838 // Return weighted average of probabilities
1839 return probs;
1840}
1841
1842//.............................................................................
1861matrixD PMNS_Base::AvgProbMatrix(int nflvi, int nflvf, double E, double dE)
1862{
1863 matrixD probs(nflvi, vectorD(nflvf, 0));
1864
1865 // Do nothing if energy is not positive
1866 if (E <= 0) return probs;
1867
1868 if (fNuPaths.empty()) return probs;
1869
1870 // Don't average zero width
1871 if (dE <= 0) return ProbMatrix(nflvi, nflvf, E);
1872
1873 vectorD LoEbin = ConvertEtoLoE(E, dE);
1874
1875 // Compute average in LoE
1876 return AvgProbMatrixLoE(nflvi, nflvf, LoEbin[0], LoEbin[1]);
1877}
1878
1879//.............................................................................
1900matrixD PMNS_Base::AvgProbMatrixLoE(int nflvi, int nflvf, double LoE,
1901 double dLoE)
1902{
1903 matrixD probs(nflvi, vectorD(nflvf, 0));
1904
1905 // Do nothing if L/E is not positive
1906 if (LoE <= 0) return probs;
1907
1908 if (fNuPaths.empty()) return probs;
1909
1910 // Make sure fPath is set
1911 // Use average if multiple paths
1913
1914 // Set the energy at bin center
1915 SetEnergy(fPath.length / LoE);
1916
1917 // Don't average zero width
1918 if (dLoE <= 0) return ProbMatrix(nflvi, nflvf);
1919
1920 // Get sample points for this bin
1921 vectorD samples = GetSamplePoints(LoE, dLoE);
1922
1923 // Variables to fill sample
1924 // probabilities and weights
1925 double sumw = 0;
1926 double length = fPath.length;
1927
1928 // Loop over all sample points
1929 for (int j = 0; j < int(samples.size()); j++) {
1930 // Set (L/E)^-2 weights
1931 double w = 1. / pow(samples[j], 2);
1932
1933 matrixD sample_probs = ProbMatrix(nflvi, nflvf, length / samples[j]);
1934
1935 for (int flvi = 0; flvi < nflvi; flvi++) {
1936 for (int flvf = 0; flvf < nflvf; flvf++) {
1937 // Add weighted probability
1938 probs[flvi][flvf] += w * sample_probs[flvi][flvf];
1939 }
1940 }
1941 // Increment sum of weights
1942 sumw += w;
1943 }
1944
1945 for (int flvi = 0; flvi < nflvi; flvi++) {
1946 for (int flvf = 0; flvf < nflvf; flvf++) {
1947 // Divide by total sampling weight
1948 probs[flvi][flvf] /= sumw;
1949 }
1950 }
1951
1952 // Return weighted average of probabilities
1953 return probs;
1954}
1955
1956//.............................................................................
1963{
1964 if (prec < 1e-8) {
1965 cerr << "WARNING: Cannot set AvgProb precision lower that 1e-8."
1966 << "Setting to 1e-8." << endl;
1967 prec = 1e-8;
1968 }
1969 fAvgProbPrec = prec;
1970}
1971
1972//.............................................................................
1985vectorD PMNS_Base::GetSamplePoints(double LoE, double dLoE)
1986{
1987 // Solve Hamiltonian to get eigenvalues
1988 SolveHam();
1989
1990 // Define conversion factor [km/GeV -> 1/(4 eV^2)]
1991 const double k1267 = kKm2eV / (4 * kGeV2eV);
1992
1993 // Get list of all effective Dm^2
1994 vectorD effDm;
1995
1996 for (int i = 0; i < fNumNus - 1; i++) {
1997 for (int j = i + 1; j < fNumNus; j++) {
1998 effDm.push_back(2 * kGeV2eV * fEnergy * fabs(fEval[j] - fEval[i]));
1999 }
2000 }
2001
2002 int numDm = effDm.size();
2003
2004 // Sort the effective Dm^2 list
2005 sort(effDm.begin(), effDm.end());
2006
2007 // Set a number of sub-divisions to achieve "good" accuracy
2008 // This needs to be studied better
2009 int n_div = ceil(200 * pow(dLoE / LoE, 0.8) / sqrt(fAvgProbPrec / 1e-4));
2010 // int n_div = 1;
2011
2012 // A vector to store sample points
2013 vectorD allSamples;
2014
2015 // Loop over sub-divisions
2016 for (int k = 0; k < n_div; k++) {
2017 // Define sub-division center and width
2018 double bctr = LoE - dLoE / 2 + (k + 0.5) * dLoE / n_div;
2019 double bwdt = dLoE / n_div;
2020
2021 // Make a vector of L/E sample values
2022 // Initialized in the sub-division center
2023 vectorD samples;
2024 samples.push_back(bctr);
2025
2026 // Loop over all Dm^2 to average each frequency
2027 // This will recursively sample points in smaller
2028 // bins so that all relevant frequencies are used
2029 for (int i = 0; i < numDm; i++) {
2030 // Copy the list of sample L/E values
2031 vectorD prev = samples;
2032
2033 // Redefine bin width to lie within full sub-division
2034 double Width =
2035 2 * min(prev[0] - (bctr - bwdt / 2), (bctr + bwdt / 2) - prev[0]);
2036
2037 // Compute oscillation argument sorted from lowest to highest
2038 const double arg = k1267 * effDm[i] * Width;
2039
2040 // Skip small oscillation values.
2041 // If it's the last one, lower the tolerance
2042 if (i < numDm - 1) {
2043 if (arg < 0.9) continue;
2044 }
2045 else {
2046 if (arg < 0.1) continue;
2047 }
2048
2049 // Reset samples to redefine them
2050 samples.clear();
2051
2052 // Loop over previous samples
2053 for (int j = 0; j < int(prev.size()); j++) {
2054 // Compute new sample points around old samples
2055 // This is based on a oscillatory quadrature rule
2056 double sample = (1 / sqrt(3)) * (Width / 2);
2057 if (arg != 0) sample = acos(sin(arg) / arg) / arg * (Width / 2);
2058
2059 // Add samples above and below center
2060 samples.push_back(prev[j] - sample);
2061 samples.push_back(prev[j] + sample);
2062 }
2063
2064 } // End of loop over Dm^2
2065
2066 // Add sub-division samples to the end of allSamples vector
2067 allSamples.insert(allSamples.end(), samples.begin(), samples.end());
2068
2069 } // End of loop over sub-divisions
2070
2071 // Return all sample points
2072 return allSamples;
2073}
2074
virtual void Propagate()
Propagate neutrino through full path.
Definition: PMNS_Base.cxx:1018
static const complexD zero
zero in complex
Definition: PMNS_Base.h:211
virtual double P(int flv)
Return the probability of final state in flavour flv.
Definition: PMNS_Base.cxx:1058
bool fIsNuBar
Anti-neutrino flag.
Definition: PMNS_Base.h:293
virtual matrixD AvgProbMatrixLoE(int nflvi, int nflvf, double LoE, double dLoE=0)
Compute the average probability matrix over a bin of L/E.
Definition: PMNS_Base.cxx:1900
virtual vectorD ConvertEtoLoE(double E, double dE)
Definition: PMNS_Base.cxx:1516
virtual void SetZoA(double zoa)
Set Z/A value for single path.
Definition: PMNS_Base.cxx:413
virtual double AvgProbLoE(vectorC nu_in, int flvf, double LoE, double dLoE=0)
Compute the average probability over a bin of L/E.
Definition: PMNS_Base.cxx:1643
virtual vectorD AvgProbVectorLoE(vectorC nu_in, double LoE, double dLoE=0)
Compute the average probability vector over a bin of L/E.
Definition: PMNS_Base.cxx:1791
vectorC fNuState
The neutrino current state.
Definition: PMNS_Base.h:283
int fNumNus
Number of neutrino flavours.
Definition: PMNS_Base.h:277
std::vector< NuPath > fNuPaths
Vector of neutrino paths.
Definition: PMNS_Base.h:295
double fEnergy
Neutrino energy.
Definition: PMNS_Base.h:292
virtual vectorC GetMassEigenstate(int mi)
Get a neutrino mass eigenstate.
Definition: PMNS_Base.cxx:795
virtual void RotateH(int i, int j, matrixC &Ham)
Rotate the Hamiltonian by theta_ij and delta_ij.
Definition: PMNS_Base.cxx:822
virtual bool GetIsNuBar()
Get the anti-neutrino flag.
Definition: PMNS_Base.cxx:261
std::unordered_set< EigenPoint > fMixCache
Caching set of eigensystems.
Definition: PMNS_Base.h:307
static const double kKm2eV
km to eV^-1
Definition: PMNS_Base.h:215
double fAvgProbPrec
AvgProb precision.
Definition: PMNS_Base.h:305
virtual void SetDm(int j, double dm)
Set the mass-splitting dm_j1 in eV^2.
Definition: PMNS_Base.cxx:674
virtual void SetDelta(int i, int j, double delta)
Set the CP phase delta_ij.
Definition: PMNS_Base.cxx:602
virtual void SetStdPars()
Set PDG 3-flavor parameters.
Definition: PMNS_Base.cxx:177
virtual double GetDmEff(int j)
Get the effective mass-splitting dm_j1 in eV^2.
Definition: PMNS_Base.cxx:732
virtual void PropagatePath(NuPath p)
Propagate neutrino through a single path.
Definition: PMNS_Base.cxx:983
virtual void SetLength(double L)
Set a single path lentgh in km.
Definition: PMNS_Base.cxx:391
matrixC fHms
matrix H*2E in eV^2
Definition: PMNS_Base.h:284
vectorC fBuffer
Buffer for neutrino state tranformations.
Definition: PMNS_Base.h:287
bool fGotES
Tag to avoid recalculating eigensystem.
Definition: PMNS_Base.h:299
virtual void SetIsNuBar(bool isNuBar)
Set the anti-neutrino flag.
Definition: PMNS_Base.cxx:243
virtual vectorD AvgProbVector(vectorC nu_in, double E, double dE=0)
Definition: PMNS_Base.cxx:1753
virtual double AvgProb(vectorC nu_in, int flvf, double E, double dE=0)
Compute the average probability over a bin of energy.
Definition: PMNS_Base.cxx:1568
int fMaxCache
Maximum cache size.
Definition: PMNS_Base.h:303
virtual void FillCache()
Cache the current eigensystem.
Definition: PMNS_Base.cxx:157
static const complexD one
one in complex
Definition: PMNS_Base.h:212
matrixC fEvec
Eigenvectors of the Hamiltonian.
Definition: PMNS_Base.h:290
virtual double Prob(vectorC nu_in, int flvf)
Compute the probability of nu_in going to flvf.
Definition: PMNS_Base.cxx:1114
virtual matrixD AvgProbMatrix(int nflvi, int nflvf, double E, double dE=0)
Definition: PMNS_Base.cxx:1861
NuPath fPath
Current neutrino path.
Definition: PMNS_Base.h:296
virtual void SetLayers(std::vector< int > lay)
Set multiple path layer indices.
Definition: PMNS_Base.cxx:519
virtual ~PMNS_Base()
Destructor.
Definition: PMNS_Base.cxx:73
virtual void SolveHam()=0
virtual void AddPath(NuPath p)
Add a path to the sequence.
Definition: PMNS_Base.cxx:307
virtual void SetEnergy(double E)
Set the neutrino energy in GeV.
Definition: PMNS_Base.cxx:226
vectorD fEval
Eigenvalues of the Hamiltonian.
Definition: PMNS_Base.h:289
bool fBuiltHms
Tag to avoid rebuilding Hms.
Definition: PMNS_Base.h:298
virtual void SetUseCache(bool u=true)
Set caching on/off.
Definition: PMNS_Base.cxx:105
virtual void SetCurPath(NuPath p)
Set the path currently in use by the class.
Definition: PMNS_Base.cxx:274
vectorC fPhases
Buffer for oscillation phases.
Definition: PMNS_Base.h:286
EigenPoint fProbe
EigenpPoint to try.
Definition: PMNS_Base.h:308
vectorD fDm
m^2_i - m^2_1 in vacuum
Definition: PMNS_Base.h:279
virtual void SetPath(NuPath p)
Set a single path.
Definition: PMNS_Base.cxx:330
virtual void SetAvgProbPrec(double prec)
Set the AvgProb precision.
Definition: PMNS_Base.cxx:1962
virtual void SetAtt(double att, int idx)
Set one of the path attributes.
Definition: PMNS_Base.cxx:364
virtual bool TryCache()
Try to find a cached eigensystem.
Definition: PMNS_Base.cxx:134
virtual void ResetToFlavour(int flv)
Reset neutrino state to pure flavour flv.
Definition: PMNS_Base.cxx:1034
virtual void SetPureState(vectorC nu_in)
Set the initial state from a pure state.
Definition: PMNS_Base.cxx:1070
virtual void ClearCache()
Clear the cache.
Definition: PMNS_Base.cxx:111
matrixD fDelta
delta[i][j] CP violating phase
Definition: PMNS_Base.h:281
virtual void SetDensity(double rho)
Set single path density in g/cm^3.
Definition: PMNS_Base.cxx:402
virtual std::vector< NuPath > GetPath()
Get the neutrino path sequence.
Definition: PMNS_Base.cxx:300
virtual vectorD ProbVector(vectorC nu_in)
Definition: PMNS_Base.cxx:1250
virtual double GetEnergy()
Get the neutrino energy in GeV.
Definition: PMNS_Base.cxx:255
virtual void SetAngle(int i, int j, double th)
Set the mixing angle theta_ij.
Definition: PMNS_Base.cxx:539
virtual double GetAngle(int i, int j)
Get the mixing angle theta_ij.
Definition: PMNS_Base.cxx:570
virtual void BuildHms()
Build the matrix of masses squared.
Definition: PMNS_Base.cxx:955
virtual double GetDm(int j)
Get the mass-splitting dm_j1 in eV^2.
Definition: PMNS_Base.cxx:696
bool fUseCache
Flag for whether to use caching.
Definition: PMNS_Base.h:301
static const double kGeV2eV
GeV to eV.
Definition: PMNS_Base.h:217
virtual double GetDelta(int i, int j)
Get the CP phase delta_ij.
Definition: PMNS_Base.cxx:638
virtual void SetStdPath()
Set standard neutrino path.
Definition: PMNS_Base.cxx:205
virtual void InitializeVectors()
Definition: PMNS_Base.cxx:79
virtual void RotateState(int i, int j)
Rotate the neutrino state by theta_ij and delta_ij.
Definition: PMNS_Base.cxx:760
virtual void SetMaxCache(int mc=1e6)
Set max cache size.
Definition: PMNS_Base.cxx:128
virtual vectorD GetSamplePoints(double LoE, double dLoE)
Compute the sample points for a bin of L/E with width dLoE.
Definition: PMNS_Base.cxx:1985
virtual void ClearPath()
Clear the path vector.
Definition: PMNS_Base.cxx:287
virtual std::vector< int > GetSortedIndices(const vectorD x)
Get indices that sort a vector.
Definition: PMNS_Base.cxx:715
virtual matrixD ProbMatrix(int nflvi, int nflvf)
Compute the probability matrix.
Definition: PMNS_Base.cxx:1387
matrixD fTheta
theta[i][j] mixing angle
Definition: PMNS_Base.h:280
virtual vectorD GetProbVector()
Definition: PMNS_Base.cxx:1233
Some useful general definitions.
Definition: Absorption.h:6
std::vector< int > vectorI
Definition: Definitions.h:16
std::complex< double > complexD
Definition: Definitions.h:21
std::vector< complexD > vectorC
Definition: Definitions.h:22
std::vector< double > vectorD
Definition: Definitions.h:18
std::vector< vectorD > matrixD
Definition: Definitions.h:19
NuPath AvgPath(NuPath &p1, NuPath &p2)
Get the average of two paths.
Definition: NuPath.cxx:27
std::vector< vectorC > matrixC
Definition: Definitions.h:23
Definition: EigenPoint.h:44
vectorD fEval
Eigenvalues to be cached.
Definition: EigenPoint.h:38
void SetVars(double e=0, NuPath p=NuPath(0, 0), bool n=false)
Set eigensystem parameters.
Definition: EigenPoint.cxx:39
matrixC fEvec
Eigenvectors to be cached.
Definition: EigenPoint.h:39
An index sorting comparator.
Definition: PMNS_Base.h:312
A struct representing a neutrino path segment.
Definition: NuPath.h:34
int layer
An index to identify the matter type.
Definition: NuPath.h:81
double density
The density of the path segment in g/cm^3.
Definition: NuPath.h:79
double length
The length of the path segment in km.
Definition: NuPath.h:78
double zoa
The effective Z/A value of the path segment.
Definition: NuPath.h:80