flexiblesusy is hosted by Hepforge, IPPP Durham
FlexibleSUSY
pmns.cpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of FlexibleSUSY.
3//
4// FlexibleSUSY is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published
6// by the Free Software Foundation, either version 3 of the License,
7// or (at your option) any later version.
8//
9// FlexibleSUSY is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with FlexibleSUSY. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
19#include "pmns.hpp"
20#include "ew_input.hpp"
21
22#include <cmath>
23#include <limits>
24
25namespace flexiblesusy {
26
27namespace {
28
29bool is_zero(double x) noexcept
30{
31 return std::abs(x) <= std::numeric_limits<double>::epsilon();
32}
33
34double sqr(double x) { return x*x; }
35
36int sign(double x) { return x >= 0.0 ? 1 : -1; }
37
38} // anonymous namespace
39
41{
42 theta_12 = 0.;
43 theta_13 = 0.;
44 theta_23 = 0.;
45 delta = 0.;
46 alpha_1 = 0.;
47 alpha_2 = 0.;
48}
49
51{
58}
59
60Eigen::Matrix<double,3,3> PMNS_parameters::get_real_pmns() const
61{
62 const std::complex<double> eID(std::polar(1.0, delta));
63 const double s12 = std::sin(theta_12);
64 const double s13 = std::sin(theta_13);
65 const double s23 = std::sin(theta_23);
66 const double c12 = std::cos(theta_12);
67 const double c13 = std::cos(theta_13);
68 const double c23 = std::cos(theta_23);
69
70 // set phase factor e^(i delta) to +1 or -1 depending on the sign
71 // of its real part
72 const int pf = sign(std::real(eID));
73
74 Eigen::Matrix<double,3,3> pmns_matrix;
75 pmns_matrix(0, 0) = c12 * c13;
76 pmns_matrix(0, 1) = s12 * c13;
77 pmns_matrix(0, 2) = pf * s13;
78 pmns_matrix(1, 0) = -s12 * c23 - pf * c12 * s23 * s13;
79 pmns_matrix(1, 1) = c12 * c23 - pf * s12 * s23 * s13;
80 pmns_matrix(1, 2) = s23 * c13;
81 pmns_matrix(2, 0) = s12 * s23 - pf * c12 * c23 * s13;
82 pmns_matrix(2, 1) = -c12 * s23 - pf * s12 * c23 * s13;
83 pmns_matrix(2, 2) = c23 * c13;
84
85 return pmns_matrix;
86}
87
88Eigen::Matrix<std::complex<double>,3,3> PMNS_parameters::get_complex_pmns() const
89{
90 const std::complex<double> eID(std::polar(1.0, delta));
91 const std::complex<double> eIAlpha1(std::polar(1.0, 0.5*alpha_1));
92 const std::complex<double> eIAlpha2(std::polar(1.0, 0.5*alpha_2));
93 const double s12 = std::sin(theta_12);
94 const double s13 = std::sin(theta_13);
95 const double s23 = std::sin(theta_23);
96 const double c12 = std::cos(theta_12);
97 const double c13 = std::cos(theta_13);
98 const double c23 = std::cos(theta_23);
99
100 Eigen::Matrix<std::complex<double>,3,3> pmns_matrix;
101 pmns_matrix(0, 0) = c12 * c13 * eIAlpha1;
102 pmns_matrix(0, 1) = s12 * c13 * eIAlpha2;
103 pmns_matrix(0, 2) = s13 / eID;
104 pmns_matrix(1, 0) = (-s12 * c23 - c12 * s23 * s13 * eID) * eIAlpha1;
105 pmns_matrix(1, 1) = (c12 * c23 - s12 * s23 * s13 * eID) * eIAlpha2;
106 pmns_matrix(1, 2) = s23 * c13;
107 pmns_matrix(2, 0) = (s12 * s23 - c12 * c23 * s13 * eID) * eIAlpha1;
108 pmns_matrix(2, 1) = (-c12 * s23 - s12 * c23 * s13 * eID) * eIAlpha2;
109 pmns_matrix(2, 2) = c23 * c13;
110
111 return pmns_matrix;
112}
113
114void PMNS_parameters::to_pdg_convention(Eigen::Matrix<double,3,3>& Vv,
115 Eigen::Matrix<double,3,3>& Ve,
116 Eigen::Matrix<double,3,3>& Ue)
117{
118 Eigen::Matrix<double,3,3> pmns(Ve*Vv.adjoint());
119 to_pdg_convention(pmns, Vv, Ve, Ue);
120}
121
122void PMNS_parameters::to_pdg_convention(Eigen::Matrix<double,3,3>& pmns,
123 Eigen::Matrix<double,3,3>& Vv,
124 Eigen::Matrix<double,3,3>& Ve,
125 Eigen::Matrix<double,3,3>& Ue)
126{
127 Eigen::Matrix<double,3,3> signs_E(Eigen::Matrix<double,3,3>::Identity());
128 Eigen::Matrix<double,3,3> signs_V(Eigen::Matrix<double,3,3>::Identity());
129
130 // make 33 element positive
131 if (pmns(2, 2) < 0.) {
132 signs_E(2, 2) = -1.;
133 for (int j = 0; j < 3; ++j) {
134 pmns(2, j) *= -1.;
135 }
136 }
137
138 // make 23 element positive
139 if (pmns(1, 2) < 0.) {
140 signs_V(2, 2) = -1;
141 signs_E(2, 2) *= -1;
142 for (int j = 0; j < 3; ++j) {
143 pmns(2, j) *= -1;
144 pmns(j, 2) *= -1;
145 }
146 }
147
148 Ve = signs_E * Ve;
149 Ue = signs_E * Ue;
150 Vv = signs_V * Vv;
151}
152
154 Eigen::Matrix<std::complex<double>,3,3>& Vv,
155 Eigen::Matrix<std::complex<double>,3,3>& Ve,
156 Eigen::Matrix<std::complex<double>,3,3>& Ue)
157{
158 Eigen::Matrix<std::complex<double>,3,3> pmns(Ve*Vv.adjoint());
159 to_pdg_convention(pmns, Vv, Ve, Ue);
160}
161
162namespace {
163
164template<typename T>
165std::complex<T> phase(const std::complex<T>& z) noexcept
166{
167 T r = std::abs(z);
168 return is_zero(r) ? 1 : z/r;
169}
170
172 const Eigen::Matrix<std::complex<double>,3,3>& pmns,
173 const std::complex<double>& p,
174 std::complex<double>& o,
175 Eigen::DiagonalMatrix<std::complex<double>,3>& l)
176{
177 o = std::conj(phase(p * pmns(0,2)));
178 l.diagonal().bottomRightCorner<2,1>() = (o * pmns.bottomRightCorner<2,1>()).
179 unaryExpr([] (const std::complex<double>& z) { return phase<double>(z); }).conjugate();
180}
181
183double sanitize_hypot(double sc) noexcept
184{
185 if (sc < -1.) { sc = -1.0; }
186 if (sc > 1.) { sc = 1.0; }
187 return sc;
188}
189
190} // anonymous namespace
191
193 Eigen::Matrix<std::complex<double>,3,3>& pmns,
194 Eigen::Matrix<std::complex<double>,3,3>& Vv,
195 Eigen::Matrix<std::complex<double>,3,3>& Ve,
196 Eigen::Matrix<std::complex<double>,3,3>& Ue)
197{
198 std::complex<double> o;
199 Eigen::DiagonalMatrix<std::complex<double>,3> l(1,1,1);
200
201 const double s13 = sanitize_hypot(std::abs(pmns(0,2)));
202 const double c13_sq = 1. - sqr(s13);
203
204 if (is_zero(c13_sq)) {
205 o = std::conj(phase(pmns(0,2)));
206 const auto rel_phase = std::sqrt(phase(pmns(1,0) * pmns(2,1)));
207 const auto p = std::conj(rel_phase * rel_phase)
208 * phase(pmns(1,0) * pmns(1,1));
209 l.diagonal()[1] = std::conj(o * rel_phase);
210 l.diagonal()[2] = std::conj(o * rel_phase) * p;
211 } else {
212 const double c13 = std::sqrt(c13_sq);
213 const double s12 = sanitize_hypot(std::abs(pmns(0,1)) / c13);
214 const double c12 = std::sqrt(1 - sqr(s12));
215 const double s23 = sanitize_hypot(std::abs(pmns(1,2)) / c13);
216 const double c23 = std::sqrt(1 - sqr(s23));
217 const double jcp = std::imag(pmns(1,2) * std::conj(pmns(0,2))
218 * pmns(0,1) * std::conj(pmns(1,1)));
219 const double side1 = s12*s23;
220 const double side2 = c12*c23*s13;
221 const double cosdelta = sanitize_hypot(
222 is_zero(jcp) ? 1 // delta is removable
223 : (sqr(side1) + sqr(side2) - std::norm(pmns(2,0))) / (2*side1*side2));
224 const double sindelta = std::sqrt(1 - sqr(cosdelta));
225 const std::complex<double> p(cosdelta, sindelta); // Exp[I delta]
226 calc_phase_factors(pmns, p, o, l);
227
228 const auto a1 = phase(o*pmns(0,0));
229 const auto a2 = phase(o*pmns(0,1));
230
231 Eigen::Matrix<std::complex<double>,2,2> pmnsBL{
232 (o * l * pmns).bottomLeftCorner<2,2>()};
233 Eigen::Array<std::complex<double>,2,2> maj_phases;
234 maj_phases << a1, a2, a1, a2;
235 const Eigen::Array<double,2,2> imagBL{
236 (maj_phases.conjugate() * pmnsBL.array()).imag()};
237 if (!((imagBL <= 0).all() || (imagBL >= 0).all())) {
238 calc_phase_factors(pmns, std::conj(p), o, l);
239 }
240 }
241
242 Ve.transpose() *= l * o;
243 Ue.transpose() *= (l * o).diagonal().conjugate().asDiagonal();
244 pmns = Ve * Vv.adjoint();
245}
246
247} // namespace flexiblesusy
double sanitize_hypot(double sc) noexcept
restrict sin or cos to interval [-1,1]
Definition: pmns.cpp:183
std::complex< T > phase(const std::complex< T > &z) noexcept
Definition: pmns.cpp:165
void calc_phase_factors(const Eigen::Matrix< std::complex< double >, 3, 3 > &pmns, const std::complex< double > &p, std::complex< double > &o, Eigen::DiagonalMatrix< std::complex< double >, 3 > &l)
Definition: pmns.cpp:171
constexpr T norm(const Complex< T > &z) noexcept
Definition: complex.hpp:66
T sqr(T x)
Definition: mathdefs.hpp:62
const Real epsilon
Definition: mathdefs.hpp:18
std::enable_if_t< std::is_unsigned< T >::value, bool > is_zero(T a, T prec=std::numeric_limits< T >::epsilon()) noexcept
compares a number for being close to zero
Definition: numerics2.hpp:46
T sign(T x)
Definition: mathdefs.hpp:65
constexpr Complex< T > conj(const Complex< T > &z) noexcept
Definition: complex.hpp:48
static void to_pdg_convention(Eigen::Matrix< double, 3, 3 > &, Eigen::Matrix< double, 3, 3 > &, Eigen::Matrix< double, 3, 3 > &, Eigen::Matrix< double, 3, 3 > &)
Definition: pmns.cpp:122
Eigen::Matrix< std::complex< double >, 3, 3 > get_complex_pmns() const
Definition: pmns.cpp:88
Eigen::Matrix< double, 3, 3 > get_real_pmns() const
Definition: pmns.cpp:60