OscProb
PMNS_Deco.cxx
Go to the documentation of this file.
1
2//
3// Implementation of oscillations of neutrinos in matter in a
4// three-neutrino framework with decoherence.
5//
6// This class inherits from the PMNS_Fast class
7//
8// jcoelho\@apc.in2p3.fr
10
11#include <cassert>
12#include <iostream>
13
14#include "PMNS_Deco.h"
15
16using namespace OscProb;
17
18using namespace std;
19
20//.............................................................................
26PMNS_Deco::PMNS_Deco()
27 : PMNS_Fast(), fGamma(), fRho(3, vectorC(3, 0)), fMBuffer(3, vectorC(3, 0))
28{
29 SetStdPath();
30 SetGamma(2, 0);
31 SetGamma(3, 0);
32 SetDecoAngle(0);
33 SetPower(0);
34}
35
36//.............................................................................
41
42//.............................................................................
51void PMNS_Deco::SetGamma(int j, double val)
52{
53 if (j < 2 || j > 3) {
54 cerr << "WARNING: Gamma_" << j << 1 << " not valid for " << fNumNus
55 << " neutrinos. Doing nothing." << endl;
56 return;
57 }
58
59 if (val < 0) {
60 cerr << "WARNING: Gamma_" << j << 1 << " must be positive. "
61 << "Setting it to absolute value of input: " << -val << endl;
62 val = -val;
63 }
64
65 fGamma[j - 1] = val;
66}
67
68//.............................................................................
84void PMNS_Deco::SetGamma32(double val)
85{
86 if (val < 0) {
87 cerr << "WARNING: Gamma_32 must be positive. "
88 << "Setting it to absolute value of input: " << -val << endl;
89 val = -val;
90 }
91
92 double min32 = 0.25 * fGamma[1];
93
94 if (fGamma[0] >= 0)
95 min32 *= 1 - pow(fGamma[0], 2);
96 else
97 min32 *= 1 + 3 * pow(fGamma[0], 2);
98
99 if (val < min32) {
100 if (fGamma[0] >= 0 || 4 * val / fGamma[1] < 1) {
101 fGamma[0] = sqrt(1 - 4 * val / fGamma[1]);
102 fGamma[2] = 0.25 * fGamma[1] * (1 + 3 * pow(fGamma[0], 2));
103 }
104 else {
105 fGamma[0] = -sqrt((4 * val / fGamma[1] - 1) / 3);
106 fGamma[2] = 0.25 * fGamma[1] * (1 - pow(fGamma[0], 2));
107 }
108
109 cerr << "WARNING: Impossible to have Gamma32 = " << val
110 << " with current Gamma21 and theta parameters." << endl
111 << " Changing the value of cos(theta) to " << fGamma[0]
112 << endl;
113
114 return;
115 }
116
117 double arg = fGamma[1] * (4 * val - fGamma[1] * (1 - pow(fGamma[0], 2)));
118
119 if (arg < 0) {
120 arg = 0;
121 fGamma[0] = sqrt(1 - 4 * val / fGamma[1]);
122 cerr << "WARNING: Imaginary Gamma31 found. Changing the value of "
123 "cos(theta) to "
124 << fGamma[0] << endl;
125 }
126
127 double gamma31 = val + fGamma[1] * pow(fGamma[0], 2) + fGamma[0] * sqrt(arg);
128
129 fGamma[2] = gamma31;
130
131 if (fabs(val - GetGamma(3, 2)) > 1e-6) {
132 cerr << "ERROR: Failed sanity check: GetGamma(3,2) = " << GetGamma(3, 2)
133 << " != " << val << endl;
134 }
135}
136
137//.............................................................................
148void PMNS_Deco::SetDecoAngle(double th) { fGamma[0] = cos(th); }
149
150//.............................................................................
161void PMNS_Deco::SetPower(double n) { fPower = n; }
162
163//.............................................................................
167double PMNS_Deco::GetDecoAngle() { return acos(fGamma[0]); }
168
169//.............................................................................
173double PMNS_Deco::GetPower() { return fPower; }
174
175//.............................................................................
185double PMNS_Deco::GetGamma(int i, int j)
186{
187 if (i < j) {
188 cerr << "WARNING: First argument should be larger than second argument"
189 << endl
190 << "Setting reverse order (Gamma_" << j << i << "). " << endl;
191 int temp = i;
192 i = j;
193 j = temp;
194 }
195 if (i < 1 || i > 3 || i <= j || j < 1) {
196 cerr << "WARNING: Gamma_" << i << j << " not valid for " << fNumNus
197 << " neutrinos. Returning 0." << endl;
198 return 0;
199 }
200
201 if (j == 1) { return fGamma[i - 1]; }
202 else {
203 // Combine Gamma31, Gamma21 and an angle (fGamma[0] = cos(th)) to make
204 // Gamma32
205 double arg =
206 fGamma[1] * (4 * fGamma[2] - fGamma[1] * (1 - pow(fGamma[0], 2)));
207
208 if (arg < 0) return fGamma[1] - 3 * fGamma[2];
209
210 return fGamma[2] + fGamma[1] * pow(fGamma[0], 2) - fGamma[0] * sqrt(arg);
211 }
212}
213
214//.............................................................................
220void PMNS_Deco::RotateState(bool to_mass)
221{
222 // buffer = rho . U
223 for (int i = 0; i < fNumNus; i++) {
224 for (int j = 0; j < fNumNus; j++) {
225 fMBuffer[i][j] = 0;
226 for (int k = 0; k < fNumNus; k++) {
227 if (to_mass)
228 fMBuffer[i][j] += fRho[i][k] * fEvec[k][j];
229 else
230 fMBuffer[i][j] += fRho[i][k] * conj(fEvec[j][k]);
231 }
232 }
233 }
234
235 // rho = U^\dagger . buffer = U^\dagger . rho . U
236 // Final matrix is Hermitian, so copy upper to lower triangle
237 for (int i = 0; i < fNumNus; i++) {
238 for (int j = i; j < fNumNus; j++) {
239 fRho[i][j] = 0;
240 for (int k = 0; k < fNumNus; k++) {
241 if (to_mass)
242 fRho[i][j] += conj(fEvec[k][i]) * fMBuffer[k][j];
243 else
244 fRho[i][j] += fEvec[i][k] * fMBuffer[k][j];
245 }
246 if (j > i) fRho[j][i] = conj(fRho[i][j]);
247 }
248 }
249}
250
251//.............................................................................
256{
257 vectorI out(3, 0);
258
259 // 1st element is smallest
260 if (x[0] < x[1] && x[0] < x[2]) {
261 // 3rd element is largest
262 if (x[1] < x[2]) {
263 out[1] = 1;
264 out[2] = 2;
265 }
266 // 2nd element is largest
267 else {
268 out[1] = 2;
269 out[2] = 1;
270 }
271 }
272 // 2nd element is smallest
273 else if (x[1] < x[2]) {
274 out[0] = 1;
275 // 3rd element is largest
276 if (x[0] < x[2]) out[2] = 2;
277 // 1st element is largest
278 else
279 out[1] = 2;
280 }
281 // 3rd element is smallest
282 else {
283 out[0] = 2;
284 // 2nd element is largest
285 if (x[0] < x[1]) out[2] = 1;
286 // 1st element is largest
287 else
288 out[1] = 1;
289 }
290
291 return out;
292}
293
294//.............................................................................
301{
302 // Set the neutrino path
303 SetCurPath(p);
304
305 // Solve for eigensystem
306 SolveHam();
307
308 // Rotate to effective mass basis
309 RotateState(true);
310
311 // Some ugly way of matching gamma and dmsqr indices
312 vectorI dm_idx = sort3(fDm);
313 vectorI ev_idx = sort3(fEval);
314
315 int idx[3];
316 for (int i = 0; i < fNumNus; i++) idx[ev_idx[i]] = dm_idx[i];
317
318 // Power law dependency of gamma parameters
319 double energyCorr = pow(fEnergy, fPower);
320
321 // Convert path length to eV
322 double lengthIneV = kKm2eV * p.length;
323
324 // Apply phase rotation to off-diagonal elements
325 for (int j = 0; j < fNumNus; j++) {
326 for (int i = 0; i < j; i++) {
327 // Get the appropriate gamma parameters based on sorted indices
328 double gamma_ij =
329 GetGamma(max(idx[i], idx[j]) + 1, min(idx[i], idx[j]) + 1) *
330 energyCorr;
331 // Multiply by path length
332 gamma_ij *= kGeV2eV * lengthIneV;
333 // This is the standard oscillation phase
334 double arg = (fEval[i] - fEval[j]) * lengthIneV;
335 // apply phase to rho
336 fRho[i][j] *= exp(-gamma_ij) * complexD(cos(arg), -sin(arg));
337 fRho[j][i] = conj(fRho[i][j]);
338 }
339 }
340
341 // Rotate back to flavour basis
342 RotateState(false);
343}
344
345//.............................................................................
357{
359
360 assert(flv >= 0 && flv < fNumNus);
361 for (int i = 0; i < fNumNus; ++i) {
362 for (int j = 0; j < fNumNus; ++j) {
363 if (i == flv && i == j)
364 fRho[i][j] = one;
365 else
366 fRho[i][j] = zero;
367 }
368 }
369}
370
371//.............................................................................
384double PMNS_Deco::P(int flv)
385{
386 assert(flv >= 0 && flv < fNumNus);
387 return abs(fRho[flv][flv]);
388}
389
390//.............................................................................
397{
398 assert(nu_in.size() == fNumNus);
399
400 for (int i = 0; i < fNumNus; i++) {
401 for (int j = 0; j < fNumNus; j++) {
402 fRho[i][j] = conj(nu_in[i]) * nu_in[j];
403 }
404 }
405}
406
407//.............................................................................
421matrixD PMNS_Deco::ProbMatrix(int nflvi, int nflvf)
422{
423 assert(nflvi <= fNumNus && nflvi >= 0);
424 assert(nflvf <= fNumNus && nflvf >= 0);
425
426 // Output probabilities
427 matrixD probs(nflvi, vectorD(nflvf));
428
429 // List of states
430 vector<matrixC> allstates(nflvi, matrixC(fNumNus, vectorC(fNumNus)));
431
432 // Reset all initial states
433 for (int i = 0; i < nflvi; i++) {
435 allstates[i] = fRho;
436 }
437
438 // Propagate all states in parallel
439 for (int i = 0; i < int(fNuPaths.size()); i++) {
440 for (int flvi = 0; flvi < nflvi; flvi++) {
441 fRho = allstates[flvi];
443 allstates[flvi] = fRho;
444 }
445 }
446
447 // Get all probabilities
448 for (int flvi = 0; flvi < nflvi; flvi++) {
449 for (int flvj = 0; flvj < nflvf; flvj++) {
450 probs[flvi][flvj] = abs(allstates[flvi][flvj][flvj]);
451 }
452 }
453
454 return probs;
455}
456
vectorI sort3(const vectorD &x)
Definition: PMNS_Deco.cxx:255
static const complexD zero
zero in complex
Definition: PMNS_Base.h:211
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
static const double kKm2eV
km to eV^-1
Definition: PMNS_Base.h:215
static const complexD one
one in complex
Definition: PMNS_Base.h:212
matrixC fEvec
Eigenvectors of the Hamiltonian.
Definition: PMNS_Base.h:290
vectorD fEval
Eigenvalues of the Hamiltonian.
Definition: PMNS_Base.h:289
virtual void SetCurPath(NuPath p)
Set the path currently in use by the class.
Definition: PMNS_Base.cxx:274
vectorD fDm
m^2_i - m^2_1 in vacuum
Definition: PMNS_Base.h:279
virtual void ResetToFlavour(int flv)
Reset neutrino state to pure flavour flv.
Definition: PMNS_Base.cxx:1034
static const double kGeV2eV
GeV to eV.
Definition: PMNS_Base.h:217
virtual void SetStdPath()
Set standard neutrino path.
Definition: PMNS_Base.cxx:205
virtual void PropagatePath(NuPath p)
Propagate neutrino through a single path.
Definition: PMNS_Deco.cxx:300
double fPower
Stores the power index parameter.
Definition: PMNS_Deco.h:73
virtual void SetGamma32(double val)
Set the parameter.
Definition: PMNS_Deco.cxx:84
matrixC fMBuffer
Some memory buffer for matrix operations.
Definition: PMNS_Deco.h:77
virtual void SetDecoAngle(double th)
Set the decoherence angle.
Definition: PMNS_Deco.cxx:148
virtual void ResetToFlavour(int flv)
Reset neutrino state to pure flavour flv.
Definition: PMNS_Deco.cxx:356
virtual ~PMNS_Deco()
Destructor.
Definition: PMNS_Deco.cxx:40
virtual double GetDecoAngle()
Get the decoherence angle.
Definition: PMNS_Deco.cxx:167
virtual double GetGamma(int i, int j)
Get any given decoherence parameter.
Definition: PMNS_Deco.cxx:185
virtual matrixD ProbMatrix(int nflvi, int nflvf)
Definition: PMNS_Deco.cxx:421
virtual void SetPureState(vectorC nu_in)
Set the density matrix from a pure state.
Definition: PMNS_Deco.cxx:396
virtual double GetPower()
Get the power index.
Definition: PMNS_Deco.cxx:173
virtual double P(int flv)
Return the probability of final state in flavour flv.
Definition: PMNS_Deco.cxx:384
virtual void RotateState(bool to_mass)
Rotate rho to/from mass basis.
Definition: PMNS_Deco.cxx:220
matrixC fRho
The neutrino density matrix state.
Definition: PMNS_Deco.h:75
virtual void SetGamma(int j, double val)
Set any given decoherence parameter.
Definition: PMNS_Deco.cxx:51
double fGamma[3]
Stores each decoherence parameter.
Definition: PMNS_Deco.h:72
virtual void SetPower(double n)
Set the power index.
Definition: PMNS_Deco.cxx:161
Implementation of oscillations of neutrinos in matter in a three-neutrino framework.
Definition: PMNS_Fast.h:40
virtual void SolveHam()
Solve the full Hamiltonian for eigenvectors and eigenvalues.
Definition: PMNS_Fast.cxx:100
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
std::vector< vectorC > matrixC
Definition: Definitions.h:23
Definition: EigenPoint.h:44
A struct representing a neutrino path segment.
Definition: NuPath.h:34
double length
The length of the path segment in km.
Definition: NuPath.h:78