26const double PMNS_Base::kGeV2eV = 1.0e+09;               
 
   27const double PMNS_Base::kKm2eV  = 1.0 / 1.973269788e-10; 
 
   28const double PMNS_Base::kNA     = 6.022140857e23; 
 
   29const double PMNS_Base::kK2 =
 
   30    1e-3 * kNA / pow(kKm2eV, 3); 
 
   31const double PMNS_Base::kGf = 1.1663787e-05; 
 
   47PMNS_Base::PMNS_Base(
int numNus)
 
   48    : fGotES(false), fBuiltHms(false), fMaxCache(1e6), fProbe(numNus)
 
  142      for (
int i = 0; i < 
fNumNus; i++) {
 
  144        for (
int j = 0; j < 
fNumNus; j++) { 
fEvec[i][j] = (*it).fEvec[i][j]; }
 
  162    for (
int i = 0; i < 
fNumNus; i++) {
 
  367    cerr << 
"WARNING: Clearing path vector and starting new single path." 
  369         << 
"To avoid possible issues, use the SetPath function." << endl;
 
  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;
 
  436    for (
int i = 0; i < nP; i++) {
 
  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;
 
  449    cerr << 
"WARNING: New vector size. Starting new path vector." << endl
 
  450         << 
"To avoid possible issues, use the SetPath function." << endl;
 
  464    for (
int i = 0; i < nA; i++) {
 
  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;
 
  521  vectorD lay_double(lay.begin(), lay.end());
 
  542    cerr << 
"WARNING: First argument should be smaller than second argument" 
  544         << 
"         Setting reverse order (Theta" << j << i << 
"). " << endl;
 
  550    cerr << 
"ERROR: Theta" << i << j << 
" not valid for " << 
fNumNus 
  551         << 
" neutrinos. Doing nothing." << endl;
 
  558  fTheta[i - 1][j - 1] = th;
 
  573    cerr << 
"WARNING: First argument should be smaller than second argument" 
  575         << 
"         Setting reverse order (Theta" << j << i << 
"). " << endl;
 
  581    cerr << 
"ERROR: Theta" << i << j << 
" not valid for " << 
fNumNus 
  582         << 
" neutrinos. Returning zero." << endl;
 
  586  return fTheta[i - 1][j - 1];
 
  605    cerr << 
"WARNING: First argument should be smaller than second argument" 
  607         << 
"         Setting reverse order (Delta" << j << i << 
"). " << endl;
 
  613    cerr << 
"ERROR: Delta" << i << j << 
" not valid for " << 
fNumNus 
  614         << 
" neutrinos. Doing nothing." << endl;
 
  618    cerr << 
"WARNING: Rotation " << i << j << 
" is real. Doing nothing." 
  626  fDelta[i - 1][j - 1] = delta;
 
  641    cerr << 
"WARNING: First argument should be smaller than second argument" 
  643         << 
"         Setting reverse order (Delta" << j << i << 
"). " << endl;
 
  649    cerr << 
"ERROR: Delta" << i << j << 
" not valid for " << 
fNumNus 
  650         << 
" neutrinos. Returning zero." << endl;
 
  654    cerr << 
"WARNING: Rotation " << i << j << 
" is real. Returning zero." 
  659  return fDelta[i - 1][j - 1];
 
  677    cerr << 
"ERROR: Dm" << j << 
"1 not valid for " << 
fNumNus 
  678         << 
" neutrinos. Doing nothing." << endl;
 
  699    cerr << 
"ERROR: Dm" << j << 
"1 not valid for " << 
fNumNus 
  700         << 
" neutrinos. Returning zero." << endl;
 
  718  for (
int i = 0; i < x.size(); i++) idx[i] = i;
 
  735    cerr << 
"ERROR: Dm_" << j << 
"1 not valid for " << 
fNumNus 
  736         << 
" neutrinos. Returning zero." << endl;
 
  745  vectorD dm_idx_double(dm_idx.begin(), dm_idx.end());
 
  750  return (
fEval[ev_idx[dm_idx[j - 1]]] - 
fEval[ev_idx[dm_idx[0]]]) * 2 *
 
  763  if (
fTheta[i][j] == 0) 
return;
 
  765  double sij = sin(
fTheta[i][j]);
 
  766  double cij = cos(
fTheta[i][j]);
 
  770  if (i + 1 == j || 
fDelta[i][j] == 0) {
 
  801  for (
int j = 0; j < 
fNumNus; j++) {
 
  825  if (
fTheta[i][j] == 0) 
return;
 
  827  double fSinBuffer = sin(
fTheta[i][j]);
 
  828  double fCosBuffer = cos(
fTheta[i][j]);
 
  840      for (
int k = 0; k < i; k++) {
 
  841        fHmsBufferC = Ham[k][i];
 
  843        Ham[k][i] *= fCosBuffer;
 
  844        Ham[k][i] += Ham[k][j] * fSinBuffer * conj(fExpBuffer);
 
  846        Ham[k][j] *= fCosBuffer;
 
  847        Ham[k][j] -= fHmsBufferC * fSinBuffer * fExpBuffer;
 
  851      for (
int k = i + 1; k < j; k++) {
 
  852        fHmsBufferC = Ham[k][j];
 
  854        Ham[k][j] *= fCosBuffer;
 
  855        Ham[k][j] -= conj(Ham[i][k]) * fSinBuffer * fExpBuffer;
 
  857        Ham[i][k] *= fCosBuffer;
 
  858        Ham[i][k] += fSinBuffer * fExpBuffer * conj(fHmsBufferC);
 
  862      fHmsBufferC = Ham[i][i];
 
  863      fHmsBufferD = real(Ham[j][j]);
 
  865      Ham[i][i] *= fCosBuffer * fCosBuffer;
 
  867          2 * fSinBuffer * fCosBuffer * real(Ham[i][j] * conj(fExpBuffer));
 
  868      Ham[i][i] += fSinBuffer * Ham[j][j] * fSinBuffer;
 
  870      Ham[j][j] *= fCosBuffer * fCosBuffer;
 
  871      Ham[j][j] += fSinBuffer * fHmsBufferC * fSinBuffer;
 
  873          2 * fSinBuffer * fCosBuffer * real(Ham[i][j] * conj(fExpBuffer));
 
  875      Ham[i][j] -= 2 * fSinBuffer * real(Ham[i][j] * conj(fExpBuffer)) *
 
  876                   fSinBuffer * fExpBuffer;
 
  878          fSinBuffer * fCosBuffer * (fHmsBufferD - fHmsBufferC) * fExpBuffer;
 
  883      for (
int k = i + 1; k < j; k++) {
 
  884        Ham[k][j] = -conj(Ham[i][k]) * fSinBuffer * fExpBuffer;
 
  886        Ham[i][k] *= fCosBuffer;
 
  890      fHmsBufferD = real(Ham[i][i]);
 
  893          fSinBuffer * fCosBuffer * (Ham[j][j] - fHmsBufferD) * fExpBuffer;
 
  895      Ham[i][i] *= fCosBuffer * fCosBuffer;
 
  896      Ham[i][i] += fSinBuffer * Ham[j][j] * fSinBuffer;
 
  898      Ham[j][j] *= fCosBuffer * fCosBuffer;
 
  899      Ham[j][j] += fSinBuffer * fHmsBufferD * fSinBuffer;
 
  907      for (
int k = 0; k < i; k++) {
 
  908        fHmsBufferC = Ham[k][i];
 
  910        Ham[k][i] *= fCosBuffer;
 
  911        Ham[k][i] += Ham[k][j] * fSinBuffer;
 
  913        Ham[k][j] *= fCosBuffer;
 
  914        Ham[k][j] -= fHmsBufferC * fSinBuffer;
 
  918      fHmsBufferC = Ham[i][i];
 
  919      fHmsBufferD = real(Ham[j][j]);
 
  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;
 
  925      Ham[j][j] *= fCosBuffer * fCosBuffer;
 
  926      Ham[j][j] += fSinBuffer * fHmsBufferC * fSinBuffer;
 
  927      Ham[j][j] -= 2 * fSinBuffer * fCosBuffer * real(Ham[i][j]);
 
  929      Ham[i][j] -= 2 * fSinBuffer * real(Ham[i][j]) * fSinBuffer;
 
  930      Ham[i][j] += fSinBuffer * fCosBuffer * (fHmsBufferD - fHmsBufferC);
 
  934      Ham[i][j] = fSinBuffer * fCosBuffer * Ham[j][j];
 
  936      Ham[i][i] = fSinBuffer * Ham[j][j] * fSinBuffer;
 
  938      Ham[j][j] *= fCosBuffer * fCosBuffer;
 
  963  for (
int j = 0; j < 
fNumNus; j++) {
 
  967    for (
int i = 0; i < j; i++) { 
fHms[i][j] = 0; }
 
  969    for (
int i = 0; i < j; i++) { 
RotateH(i, j, 
fHms); }
 
  992  for (
int i = 0; i < 
fNumNus; i++) {
 
  993    double arg = 
fEval[i] * LengthIneV;
 
  997  for (
int i = 0; i < 
fNumNus; i++) {
 
  999    for (
int j = 0; j < 
fNumNus; j++) {
 
 1006  for (
int i = 0; i < 
fNumNus; i++) {
 
 1008    for (
int j = 0; j < 
fNumNus; j++) {
 
 1036  assert(flv >= 0 && flv < 
fNumNus);
 
 1037  for (
int i = 0; i < 
fNumNus; ++i) {
 
 1060  assert(flv >= 0 && flv < 
fNumNus);
 
 1072  assert(nu_in.size() == 
fNumNus);
 
 1142  return Prob(nu_in, flvf);
 
 1164  return Prob(flvi, flvf);
 
 1194  return Prob(nu_in, flvf);
 
 1224  return Prob(flvi, flvf);
 
 1237  for (
int i = 0; i < probs.size(); i++) { probs[i] = 
P(i); }
 
 1389  assert(nflvi <= fNumNus && nflvi >= 0);
 
 1390  assert(nflvf <= fNumNus && nflvf >= 0);
 
 1399  for (
int i = 0; i < nflvi; i++) {
 
 1405  for (
int i = 0; i < int(
fNuPaths.size()); i++) {
 
 1406    for (
int flvi = 0; flvi < nflvi; flvi++) {
 
 1414  for (
int flvi = 0; flvi < nflvi; flvi++) {
 
 1415    for (
int flvj = 0; flvj < nflvf; flvj++) {
 
 1416      probs[flvi][flvj] = norm(allstates[flvi][flvj]);
 
 1526  double minE = 0.1 * E;
 
 1530  if (E - dE / 2 > minE) {
 
 1571  if (E <= 0) 
return 0;
 
 1576  if (dE <= 0) 
return Prob(nu_in, flvf, E);
 
 1581  return AvgProbLoE(nu_in, flvf, LoEbin[0], LoEbin[1]);
 
 1646  if (LoE <= 0) 
return 0;
 
 1658  if (dLoE <= 0) 
return Prob(nu_in, flvf);
 
 1670  for (
int j = 0; j < int(samples.size()); j++) {
 
 1672    double w = 1. / pow(samples[j], 2);
 
 1675    prob += w * 
Prob(nu_in, flvf, length / samples[j]);
 
 1758  if (E <= 0) 
return probs;
 
 1760  if (
fNuPaths.empty()) 
return probs;
 
 1796  if (LoE <= 0) 
return probs;
 
 1798  if (
fNuPaths.empty()) 
return probs;
 
 1819  for (
int j = 0; j < int(samples.size()); j++) {
 
 1821    double w = 1. / pow(samples[j], 2);
 
 1825    for (
int i = 0; i < 
fNumNus; i++) {
 
 1827      probs[i] += w * sample_probs[i];
 
 1833  for (
int i = 0; i < 
fNumNus; i++) {
 
 1866  if (E <= 0) 
return probs;
 
 1868  if (
fNuPaths.empty()) 
return probs;
 
 1871  if (dE <= 0) 
return ProbMatrix(nflvi, nflvf, E);
 
 1906  if (LoE <= 0) 
return probs;
 
 1908  if (
fNuPaths.empty()) 
return probs;
 
 1918  if (dLoE <= 0) 
return ProbMatrix(nflvi, nflvf);
 
 1929  for (
int j = 0; j < int(samples.size()); j++) {
 
 1931    double w = 1. / pow(samples[j], 2);
 
 1935    for (
int flvi = 0; flvi < nflvi; flvi++) {
 
 1936      for (
int flvf = 0; flvf < nflvf; flvf++) {
 
 1938        probs[flvi][flvf] += w * sample_probs[flvi][flvf];
 
 1945  for (
int flvi = 0; flvi < nflvi; flvi++) {
 
 1946    for (
int flvf = 0; flvf < nflvf; flvf++) {
 
 1948      probs[flvi][flvf] /= sumw;
 
 1965    cerr << 
"WARNING: Cannot set AvgProb precision lower that 1e-8." 
 1966         << 
"Setting to 1e-8." << endl;
 
 1996  for (
int i = 0; i < 
fNumNus - 1; i++) {
 
 1997    for (
int j = i + 1; j < 
fNumNus; j++) {
 
 2002  int numDm = effDm.size();
 
 2005  sort(effDm.begin(), effDm.end());
 
 2009  int n_div = ceil(200 * pow(dLoE / LoE, 0.8) / sqrt(
fAvgProbPrec / 1e-4));
 
 2016  for (
int k = 0; k < n_div; k++) {
 
 2018    double bctr = LoE - dLoE / 2 + (k + 0.5) * dLoE / n_div;
 
 2019    double bwdt = dLoE / n_div;
 
 2024    samples.push_back(bctr);
 
 2029    for (
int i = 0; i < numDm; i++) {
 
 2035          2 * min(prev[0] - (bctr - bwdt / 2), (bctr + bwdt / 2) - prev[0]);
 
 2038      const double arg = k1267 * effDm[i] * Width;
 
 2042      if (i < numDm - 1) {
 
 2043        if (arg < 0.9) 
continue;
 
 2046        if (arg < 0.1) 
continue;
 
 2053      for (
int j = 0; j < int(prev.size()); j++) {
 
 2056        double sample = (1 / sqrt(3)) * (Width / 2);
 
 2057        if (arg != 0) sample = acos(sin(arg) / arg) / arg * (Width / 2);
 
 2060        samples.push_back(prev[j] - sample);
 
 2061        samples.push_back(prev[j] + sample);
 
 2067    allSamples.insert(allSamples.end(), samples.begin(), samples.end());
 
virtual void Propagate()
Propagate neutrino through full path.
 
static const complexD zero
zero in complex
 
virtual double P(int flv)
Return the probability of final state in flavour flv.
 
bool fIsNuBar
Anti-neutrino flag.
 
virtual matrixD AvgProbMatrixLoE(int nflvi, int nflvf, double LoE, double dLoE=0)
Compute the average probability matrix over a bin of L/E.
 
virtual vectorD ConvertEtoLoE(double E, double dE)
 
virtual void SetZoA(double zoa)
Set Z/A value for single path.
 
virtual double AvgProbLoE(vectorC nu_in, int flvf, double LoE, double dLoE=0)
Compute the average probability over a bin of L/E.
 
virtual vectorD AvgProbVectorLoE(vectorC nu_in, double LoE, double dLoE=0)
Compute the average probability vector over a bin of L/E.
 
vectorC fNuState
The neutrino current state.
 
int fNumNus
Number of neutrino flavours.
 
std::vector< NuPath > fNuPaths
Vector of neutrino paths.
 
double fEnergy
Neutrino energy.
 
virtual vectorC GetMassEigenstate(int mi)
Get a neutrino mass eigenstate.
 
virtual void RotateH(int i, int j, matrixC &Ham)
Rotate the Hamiltonian by theta_ij and delta_ij.
 
virtual bool GetIsNuBar()
Get the anti-neutrino flag.
 
std::unordered_set< EigenPoint > fMixCache
Caching set of eigensystems.
 
static const double kKm2eV
km to eV^-1
 
double fAvgProbPrec
AvgProb precision.
 
virtual void SetDm(int j, double dm)
Set the mass-splitting dm_j1 in eV^2.
 
virtual void SetDelta(int i, int j, double delta)
Set the CP phase delta_ij.
 
virtual void SetStdPars()
Set PDG 3-flavor parameters.
 
virtual double GetDmEff(int j)
Get the effective mass-splitting dm_j1 in eV^2.
 
virtual void PropagatePath(NuPath p)
Propagate neutrino through a single path.
 
virtual void SetLength(double L)
Set a single path lentgh in km.
 
matrixC fHms
matrix H*2E in eV^2
 
vectorC fBuffer
Buffer for neutrino state tranformations.
 
bool fGotES
Tag to avoid recalculating eigensystem.
 
virtual void SetIsNuBar(bool isNuBar)
Set the anti-neutrino flag.
 
virtual vectorD AvgProbVector(vectorC nu_in, double E, double dE=0)
 
virtual double AvgProb(vectorC nu_in, int flvf, double E, double dE=0)
Compute the average probability over a bin of energy.
 
int fMaxCache
Maximum cache size.
 
virtual void FillCache()
Cache the current eigensystem.
 
static const complexD one
one in complex
 
matrixC fEvec
Eigenvectors of the Hamiltonian.
 
virtual double Prob(vectorC nu_in, int flvf)
Compute the probability of nu_in going to flvf.
 
virtual matrixD AvgProbMatrix(int nflvi, int nflvf, double E, double dE=0)
 
NuPath fPath
Current neutrino path.
 
virtual void SetLayers(std::vector< int > lay)
Set multiple path layer indices.
 
virtual ~PMNS_Base()
Destructor.
 
virtual void SolveHam()=0
 
virtual void AddPath(NuPath p)
Add a path to the sequence.
 
virtual void SetEnergy(double E)
Set the neutrino energy in GeV.
 
vectorD fEval
Eigenvalues of the Hamiltonian.
 
bool fBuiltHms
Tag to avoid rebuilding Hms.
 
virtual void SetUseCache(bool u=true)
Set caching on/off.
 
virtual void SetCurPath(NuPath p)
Set the path currently in use by the class.
 
vectorC fPhases
Buffer for oscillation phases.
 
EigenPoint fProbe
EigenpPoint to try.
 
vectorD fDm
m^2_i - m^2_1 in vacuum
 
virtual void SetPath(NuPath p)
Set a single path.
 
virtual void SetAvgProbPrec(double prec)
Set the AvgProb precision.
 
virtual void SetAtt(double att, int idx)
Set one of the path attributes.
 
virtual bool TryCache()
Try to find a cached eigensystem.
 
virtual void ResetToFlavour(int flv)
Reset neutrino state to pure flavour flv.
 
virtual void SetPureState(vectorC nu_in)
Set the initial state from a pure state.
 
virtual void ClearCache()
Clear the cache.
 
matrixD fDelta
delta[i][j] CP violating phase
 
virtual void SetDensity(double rho)
Set single path density in g/cm^3.
 
virtual std::vector< NuPath > GetPath()
Get the neutrino path sequence.
 
virtual vectorD ProbVector(vectorC nu_in)
 
virtual double GetEnergy()
Get the neutrino energy in GeV.
 
virtual void SetAngle(int i, int j, double th)
Set the mixing angle theta_ij.
 
virtual double GetAngle(int i, int j)
Get the mixing angle theta_ij.
 
virtual void BuildHms()
Build the matrix of masses squared.
 
virtual double GetDm(int j)
Get the mass-splitting dm_j1 in eV^2.
 
bool fUseCache
Flag for whether to use caching.
 
static const double kGeV2eV
GeV to eV.
 
virtual double GetDelta(int i, int j)
Get the CP phase delta_ij.
 
virtual void SetStdPath()
Set standard neutrino path.
 
virtual void InitializeVectors()
 
virtual void RotateState(int i, int j)
Rotate the neutrino state by theta_ij and delta_ij.
 
virtual void SetMaxCache(int mc=1e6)
Set max cache size.
 
virtual vectorD GetSamplePoints(double LoE, double dLoE)
Compute the sample points for a bin of L/E with width dLoE.
 
virtual void ClearPath()
Clear the path vector.
 
virtual std::vector< int > GetSortedIndices(const vectorD x)
Get indices that sort a vector.
 
virtual matrixD ProbMatrix(int nflvi, int nflvf)
Compute the probability matrix.
 
matrixD fTheta
theta[i][j] mixing angle
 
virtual vectorD GetProbVector()
 
Some useful general definitions.
 
std::vector< int > vectorI
 
std::complex< double > complexD
 
std::vector< complexD > vectorC
 
std::vector< double > vectorD
 
std::vector< vectorD > matrixD
 
NuPath AvgPath(NuPath &p1, NuPath &p2)
Get the average of two paths.
 
std::vector< vectorC > matrixC
 
vectorD fEval
Eigenvalues to be cached.
 
void SetVars(double e=0, NuPath p=NuPath(0, 0), bool n=false)
Set eigensystem parameters.
 
matrixC fEvec
Eigenvectors to be cached.
 
An index sorting comparator.
 
A struct representing a neutrino path segment.
 
int layer
An index to identify the matter type.
 
double density
The density of the path segment in g/cm^3.
 
double length
The length of the path segment in km.
 
double zoa
The effective Z/A value of the path segment.