GM2Calc 2.3.0
Loading...
Searching...
No Matches
MSSMNoFV_onshell.cpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of GM2Calc.
3//
4// GM2Calc 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// GM2Calc 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 GM2Calc. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
20#include "gm2calc/gm2_error.hpp"
21
23#include "gm2_constants.hpp"
24#include "gm2_eigen_utils.hpp"
25#include "gm2_log.hpp"
26#include "gm2_mf.hpp"
27#include "gm2_numerics.hpp"
28
29#include <algorithm>
30#include <cmath>
31#include <complex>
32#include <iostream>
33#include <limits>
34#include <sstream>
35#include <string>
36
37#include <boost/math/tools/roots.hpp>
38
39namespace gm2calc {
40
41namespace {
42 const double Pi = 3.141592653589793;
43 const double eps = std::numeric_limits<double>::epsilon();
44 const double root2 = 1.414213562373095; // Sqrt[2]
45
46 /// calculates gauge coupling from alpha
47 double calculate_e(double alpha) {
48 return std::sqrt(4. * Pi * alpha);
49 }
50
51 /// calculates alpha from gauge coupling
52 double calculate_alpha(double e) {
53 return e * e / (4. * Pi);
54 }
55
56 /// prints Eigen Matrix/Array row in pretty format
57 template <class Derived>
58 void print_row(std::ostream& str, const Eigen::DenseBase<Derived>& row)
59 {
60 str << '{';
61 if (row.rows() > 0) {
62 str << row(0);
63 for (int i = 1; i < row.cols(); ++i) {
64 str << ", " << row(i);
65 }
66 }
67 str << '}';
68 }
69
70 /// prints Eigen Matrix/Array in pretty format
71 template <class Derived>
72 std::string pretty_print(const Eigen::DenseBase<Derived>& v)
73 {
74 std::ostringstream sstr;
75
76 if (v.rows() == 1) {
77 print_row(sstr, v.row(0));
78 } else {
79 sstr << '{';
80 if (v.rows() > 0) {
81 print_row(sstr, v.row(0));
82 for (int r = 1; r < v.rows(); ++r) {
83 sstr << ", ";
84 print_row(sstr, v.row(r));
85 }
86 }
87 sstr << '}';
88 }
89
90 return sstr.str();
91 }
92
93} // anonymous namespace
94
95namespace detail {
96
97/**
98 * Returns index of most bino-like neutralino. The function extracts
99 * this information from the given neutralino mixing matrix.
100 *
101 * @param ZN neutralino mixing matrix
102 */
103template <class Derived>
104unsigned find_bino_like_neutralino(const Eigen::MatrixBase<Derived>& ZN)
105{
106 unsigned max_bino = 0;
107 ZN.col(0).cwiseAbs2().maxCoeff(&max_bino);
108
109 return max_bino;
110}
111
112/**
113 * Returns index of most right-handed smuon. The function extracts
114 * this information from the given smuon mixing matrix.
115 *
116 * @param ZM smuon mixing matrix
117 */
118template <class Derived>
119unsigned find_right_like_smuon(const Eigen::MatrixBase<Derived>& ZM)
120{
121 return (std::norm(ZM(0,0)) > std::norm(ZM(0,1))) ? 1 : 0;
122}
123
124} // namespace detail
125
126MSSMNoFV_onshell::MSSMNoFV_onshell()
129{
131 get_physical().MFt = MT;
133 get_physical().MFe = ME;
134 get_physical().MFm = MM;
136 get_physical().MVWm = MW;
137 get_physical().MVZ = MZ;
138 set_scale(get_physical().MVZ);
139}
140
141void MSSMNoFV_onshell::set_alpha_MZ(double alpha)
142{
143 EL = calculate_e(alpha);
144}
145
146void MSSMNoFV_onshell::set_alpha_thompson(double alpha)
147{
148 EL0 = calculate_e(alpha);
149}
150
151void MSSMNoFV_onshell::set_TB(double tanb)
152{
153 const double vev = get_vev();
154 const double rt = std::sqrt(1 + tanb*tanb);
155 const double sinb = tanb / rt;
156 const double cosb = 1. / rt;
157 set_vd(vev * cosb);
158 set_vu(vev * sinb);
159}
160
161double MSSMNoFV_onshell::get_vev() const
162{
163 const double cW = get_MW() / get_MZ();
164 const double g2 = get_EL() / std::sqrt(1. - cW*cW);
165 const double vev = 2. * get_MW() / g2;
166
167 return vev;
168}
169
170double MSSMNoFV_onshell::get_TB() const
171{
172 if (is_zero(get_vd(), eps)) {
173 throw EInvalidInput("down-type VEV vd = 0");
174 }
175 return get_vu() / get_vd();
176}
177
178/**
179 * Converts the model parameters from the DR-bar scheme to the mixed
180 * on-shell/DR-bar scheme.
181 *
182 * The function assumes that the physical struct is filled with SM and
183 * SUSY pole masses and corresponding mixing matrices. From these
184 * quantities, the model parameters are calculated in the mixed
185 * on-shell/DR-bar scheme, used to calculate amu.
186 *
187 * This function is intended to be used with input parameters in the
188 * (SLHA-compatible) DR-bar scheme.
189 *
190 * @param precision accuracy goal for the conversion
191 * @param max_iterations maximum number of iterations
192 */
193void MSSMNoFV_onshell::convert_to_onshell(
194 double precision, unsigned max_iterations)
195{
196 check_input();
198 copy_susy_masses_to_pole();
199
200 calculate_mb_DRbar_MZ();
201 convert_gauge_couplings();
202 convert_BMu();
203 convert_vev();
204 convert_yukawa_couplings_treelevel();
205 convert_Mu_M1_M2(precision, max_iterations);
206 convert_yukawa_couplings(); // first guess of resummed yukawas
207 convert_ml2();
208 convert_yukawa_couplings();
209 calculate_MSm(); // calculate MSm with new value of ml2(1,1) and ym
210 convert_me2(precision, max_iterations);
211 convert_yukawa_couplings();
212
213 // final mass spectrum
216 check_problems();
217}
218
219/**
220 * Calculates the SUSY mass spectrum in the mixed on-shell/DR-bar scheme.
221 *
222 * The function assumes that the physical struct is filled with SM
223 * pole masses and the SUSY parameters are given in GM2Calc-specific
224 * mixed on-shell/DR-bar scheme. From these input quantities, the
225 * corresponding (mixed on-shell/DR-bar) SUSY mass spectrum is
226 * calculated.
227 *
228 * This function is inteded to be used with the input parameters given
229 * in the GM2Calc-specific on-shell/DR-bar scheme.
230 */
231void MSSMNoFV_onshell::calculate_masses()
232{
233 check_input();
234 calculate_mb_DRbar_MZ();
235 convert_gauge_couplings();
236 convert_BMu();
237 convert_vev();
238 convert_yukawa_couplings_treelevel();
239 convert_yukawa_couplings(); // tan(beta) resummation in Yukawas
240
241 // final mass spectrum
244 check_problems();
245
246 // copy SUSY masses to physical struct
247 copy_susy_masses_to_pole();
250}
251
252/**
253 * Converts parameters and masses to the case of no tan(beta)
254 * resummation.
255 */
256void MSSMNoFV_onshell::convert_to_non_tan_beta_resummed()
257{
258 convert_yukawa_couplings_treelevel();
260 check_problems();
261}
262
263void MSSMNoFV_onshell::check_input() const
264{
265#define WARN_OR_THROW_IF(cond,msg) \
266 if (cond) { \
267 if (do_force_output()) { \
268 WARNING(msg); \
269 } else { \
270 throw EInvalidInput(msg); \
271 } \
272 }
273
274#define WARN_OR_THROW_IF_ZERO(mass,msg) \
275 WARN_OR_THROW_IF(is_zero(get_##mass(), eps), msg)
276
277 const double MW = get_MW();
278 const double MZ = get_MZ();
279 const double TB = get_TB();
280
281 WARN_OR_THROW_IF(MW >= MZ , "MW >= MZ cannot be treated with GM2Calc");
282 WARN_OR_THROW_IF_ZERO(MW , "W mass is zero");
283 WARN_OR_THROW_IF_ZERO(MZ , "Z mass is zero");
284 WARN_OR_THROW_IF_ZERO(MM , "Muon mass is zero");
285 WARN_OR_THROW_IF_ZERO(Mu , "mu parameter is zero");
286 WARN_OR_THROW_IF_ZERO(MassB , "Bino mass M1 is zero");
287 WARN_OR_THROW_IF_ZERO(MassWB, "Wino mass M2 is zero");
288 WARN_OR_THROW_IF_ZERO(TB , "tan(beta) is zero");
289 WARN_OR_THROW_IF(!std::isfinite(TB), "tan(beta) is infinite");
290
291#undef WARN_OR_THROW_IF
292#undef WARN_OR_THROW_IF_ZERO
293}
294
295void MSSMNoFV_onshell::check_problems() const
296{
297 if (get_problems().have_problem()) {
298 if (!do_force_output()) {
299 throw EPhysicalProblem(get_problems().get_problems());
300 }
301 }
302 if (get_mu2().diagonal().minCoeff() < 0. ||
303 get_md2().diagonal().minCoeff() < 0. ||
304 get_mq2().diagonal().minCoeff() < 0. ||
305 get_me2().diagonal().minCoeff() < 0. ||
306 get_ml2().diagonal().minCoeff() < 0.) {
307 if (!do_force_output()) {
308 throw EInvalidInput("soft mass squared < 0");
309 }
310 }
311 if (is_zero(get_MCha(0), eps)) {
312 if (!do_force_output()) {
313 throw EInvalidInput("lightest chargino mass = 0");
314 }
315 }
316}
317
318void MSSMNoFV_onshell::copy_susy_masses_to_pole()
319{
320 // if pole masses are zero, interpret the tree-level masses as pole
321 // masses
322
323#define COPY_IF_ZERO_0(m) \
324 if (is_zero(get_physical().m, eps)) { \
325 get_physical().m = get_##m(); \
326 }
327#define COPY_IF_ZERO_1(m,z) \
328 if (is_zero(get_physical().m, eps)) { \
329 get_physical().m = get_##m(); \
330 get_physical().z = get_##z(); \
331 }
332#define COPY_IF_ZERO_2(m,u,v) \
333 if (is_zero(get_physical().m, eps)) { \
334 get_physical().m = get_##m(); \
335 get_physical().u = get_##u(); \
336 get_physical().v = get_##v(); \
337 }
338
339 COPY_IF_ZERO_1(MChi, ZN);
340 COPY_IF_ZERO_2(MCha, UM, UP);
341 COPY_IF_ZERO_0(MSveL);
342 COPY_IF_ZERO_0(MSvmL);
343 COPY_IF_ZERO_0(MSvtL);
344 COPY_IF_ZERO_1(MSd, ZD);
345 COPY_IF_ZERO_1(MSu, ZU);
346 COPY_IF_ZERO_1(MSe, ZE);
347 COPY_IF_ZERO_1(MSm, ZM);
348 COPY_IF_ZERO_1(MStau, ZTau);
349 COPY_IF_ZERO_1(MSs, ZS);
350 COPY_IF_ZERO_1(MSc, ZC);
351 COPY_IF_ZERO_1(MSb, ZB);
352 COPY_IF_ZERO_1(MSt, ZT);
353
354#undef COPY_IF_ZERO_0
355#undef COPY_IF_ZERO_1
356#undef COPY_IF_ZERO_2
357}
358
359void MSSMNoFV_onshell::convert_gauge_couplings()
360{
361 const double MW = get_MW(); // pole mass
362 const double MZ = get_MZ(); // pole mass
363 const double cW = MW / MZ; // on-shell weak mixing angle
364
365 set_g1(std::sqrt(5. / 3.) * EL / cW);
366 set_g2(EL / std::sqrt(1. - sqr(cW)));
367}
368
369void MSSMNoFV_onshell::convert_BMu()
370{
371 const double TB = get_TB(); // DR-bar
372 const double MA = get_MA0(); // pole mass
373 const double sin2b = 2. * TB / (1. + sqr(TB));
374
375 set_BMu(0.5 * sqr(MA) * sin2b);
376}
377
378void MSSMNoFV_onshell::convert_vev()
379{
380 const double TB = get_TB(); // DR-bar
381 const double MW = get_MW(); // pole mass
382 const double vev = 2. * MW / get_g2();
383
384 set_vu(vev / std::sqrt(1. + 1. / sqr(TB)));
385 set_vd(get_vu() / TB);
386}
387
388/**
389 * Calculates mb(MZ) in DR-bar scheme.
390 *
391 * mb(MZ) DR-bar is calculated from mb(mb) MS-bar using the function
392 * \a calculate_mb_SM5_DRbar .
393 */
394void MSSMNoFV_onshell::calculate_mb_DRbar_MZ()
395{
396 const double mb_mb = get_MBMB();
397 const double alpha_s = calculate_alpha(get_g3());
398
399 mb_DRbar_MZ = calculate_mb_SM5_DRbar(mb_mb, alpha_s, get_MZ());
400}
401
402void MSSMNoFV_onshell::convert_yukawa_couplings_treelevel()
403{
404 Eigen::Matrix<double,3,3> Ye_neu(Eigen::Matrix<double,3,3>::Zero());
405 Ye_neu(0, 0) = root2 * get_ME() / get_vd();
406 Ye_neu(1, 1) = root2 * get_MM() / get_vd();
407 Ye_neu(2, 2) = root2 * get_ML() / get_vd();
408 set_Ye(Ye_neu);
409
410 Eigen::Matrix<double,3,3> Yu_neu(Eigen::Matrix<double,3,3>::Zero());
411 Yu_neu(0, 0) = root2 * get_MU() / get_vu();
412 Yu_neu(1, 1) = root2 * get_MC() / get_vu();
413 Yu_neu(2, 2) = root2 * get_MT() / get_vu();
414 set_Yu(Yu_neu);
415
416 Eigen::Matrix<double,3,3> Yd_neu(Eigen::Matrix<double,3,3>::Zero());
417 Yd_neu(0, 0) = root2 * get_MD() / get_vd();
418 Yd_neu(1, 1) = root2 * get_MS() / get_vd();
419 Yd_neu(2, 2) = root2 * get_MB() / get_vd();
420 set_Yd(Yd_neu);
421
422 // recalculate trilinear couplings with new Yukawas
423 set_TYe(Ye_neu * Ae);
424 set_TYu(Yu_neu * Au);
425 set_TYd(Yd_neu * Ad);
426}
427
428/**
429 * Calculate Yukawa couplings with resummed tan(beta) corrections
430 *
431 * @note The resummations depend on the model parameters ml2, me2, Mu,
432 * MassB, MassWB, MassG. Therefore, this routine needs to be called
433 * after all these model parameters have been determined.
434 */
435void MSSMNoFV_onshell::convert_yukawa_couplings()
436{
437 Eigen::Matrix<double,3,3> Ye_neu(Eigen::Matrix<double,3,3>::Zero());
438 Ye_neu(0, 0) = root2 * get_ME() / get_vd();
439 Ye_neu(1, 1) = root2 * get_MM() / get_vd() / (1 + delta_mu_correction(*this));
440 Ye_neu(2, 2) = root2 * get_ML() / get_vd() / (1 + delta_tau_correction(*this));
441 set_Ye(Ye_neu);
442
443 Eigen::Matrix<double,3,3> Yu_neu(Eigen::Matrix<double,3,3>::Zero());
444 Yu_neu(0, 0) = root2 * get_MU() / get_vu();
445 Yu_neu(1, 1) = root2 * get_MC() / get_vu();
446 Yu_neu(2, 2) = root2 * get_MT() / get_vu();
447 set_Yu(Yu_neu);
448
449 Eigen::Matrix<double,3,3> Yd_neu(Eigen::Matrix<double,3,3>::Zero());
450 Yd_neu(0, 0) = root2 * get_MD() / get_vd();
451 Yd_neu(1, 1) = root2 * get_MS() / get_vd();
452 Yd_neu(2, 2) = root2 * get_MB() / get_vd() / (1 + delta_bottom_correction(*this));
453 set_Yd(Yd_neu);
454
455 // recalculate trilinear couplings with new Yukawas
456 set_TYe(Ye_neu * Ae);
457 set_TYu(Yu_neu * Au);
458 set_TYd(Yd_neu * Ad);
459}
460
461/**
462 * Finds index of neutralino, which is most bino like.
463 * @return index in neutralino mass multiplet
464 */
465unsigned MSSMNoFV_onshell::find_bino_like_neutralino()
466{
467 // try using pole mass mixing matrix ZN
468 if (!gm2calc::is_zero(get_physical().ZN.cwiseAbs().maxCoeff(), eps)) {
470 }
471
472 // try using DR mixing matrix ZN
475 }
476
478}
479
480/**
481 * Determines the Mu parameter and the soft-breaking Bino and Wino
482 * mass parameters from the two chargino pole masses and the most
483 * bino-like neutralino pole mass. The function uses a fixed-point
484 * iteration.
485 *
486 * @param precision_goal precision goal of iteration
487 * @param max_iterations maximum number of iterations
488 */
489void MSSMNoFV_onshell::convert_Mu_M1_M2(
490 double precision_goal,
491 unsigned max_iterations)
492{
493 const auto bino_idx_pole = find_bino_like_neutralino();
495 const auto MCha_goal(get_physical().MCha);
496 auto MChi_goal(get_MChi());
498
499 if (verbose_output) {
500 VERBOSE("Converting Mu, M1, M2 to on-shell scheme ...\n"
501 " Goal: MCha = " << pretty_print(MCha_goal.transpose())
502 << ", MChi(" << bino_idx_DR << ") = " << MChi_goal(bino_idx_DR)
503 << ", accuracy goal = " << precision_goal);
504 }
505
506 auto calc_precision = [&MCha_goal, &MChi_goal, this] (unsigned idx) {
507 return std::max((MCha_goal - get_MCha()).cwiseAbs().maxCoeff(),
508 std::abs(MChi_goal(idx) - get_MChi(idx)));
509 };
510
511 double precision = calc_precision(bino_idx_DR);
512 unsigned it = 0;
513
514 while (precision > precision_goal && it < max_iterations) {
515
516 const auto U(get_UM()); // neg. chargino mixing matrix
517 const auto V(get_UP()); // pos. chargino mixing matrix
518 const auto N(get_ZN()); // neutralino mixing matrix
519 const Eigen::Matrix<double,2,2> X = (U.transpose() * MCha_goal.matrix().asDiagonal() * V).real();
520 const Eigen::Matrix<double,4,4> Y = (N.transpose() * MChi_goal.matrix().asDiagonal() * N).real();
521
522 if (!X.allFinite()) {
523 WARNING("chargino mixing matrix contains NaNs");
524 break;
525 }
526
527 if (!Y.allFinite()) {
528 WARNING("neutralino mixing matrix contains NaNs");
529 break;
530 }
531
532 set_MassB(Y(0,0));
533 set_MassWB(X(0,0));
534 set_Mu(X(1,1));
535
538
540
543
544 const double old_precision = precision;
545 precision = calc_precision(bino_idx_DR);
546
547 if (precision >= old_precision) {
548 if (verbose_output) {
549 VERBOSE(" No improvement in last iteration step, stopping iteration ...");
550 }
551 break;
552 }
553
554 if (verbose_output) {
555 VERBOSE(" Iteration " << it << ": Mu = " << get_Mu()
556 << ", M1 = " << get_MassB()
557 << ", M2 = " << get_MassWB()
558 << ", MCha = " << pretty_print(get_MCha().transpose())
559 << ", MChi(" << bino_idx_DR << ") = " << get_MChi(bino_idx_DR)
560 << ", accuracy = " << precision << " GeV");
561 }
562
563 it++;
564 }
565
567
568 if (precision > precision_goal) {
570 } else {
572 }
573
574 if (verbose_output) {
575 if (precision > precision_goal) {
576 VERBOSE(
577 " DR-bar to on-shell conversion for Mu, M1 and M2 did"
578 " not converge (reached absolute accuracy: " << precision <<
579 " GeV, accuracy goal: " << precision_goal <<
580 ", max. iterations: " << max_iterations << ")");
581 }
582 VERBOSE(" Achieved absolute accuracy: " << precision << " GeV");
583 }
584}
585
586/**
587 * Determines soft-breaking left-handed smuon mass parameter from the
588 * muon sneutrino pole mass.
589 */
590void MSSMNoFV_onshell::convert_ml2()
591{
592 const double MSvmL_pole = get_physical().MSvmL;
593 const double vd2 = sqr(get_vd());
594 const double vu2 = sqr(get_vu());
595 const double g12 = sqr(get_g1());
596 const double g22 = sqr(get_g2());
597
598 if (verbose_output) {
599 VERBOSE("Converting msl(2,2) to on-shell scheme ...\n"
600 " Using MSvm_pole = " << MSvmL_pole);
601 }
602
603 // calculate ml2(1,1) from muon sneutrino pole mass
604 const double ml211
605 = sqr(MSvmL_pole) + 0.125*(0.6*g12*(vu2 - vd2) + g22*(vu2 - vd2));
606
607 if (std::isfinite(ml211)) {
608 set_ml2(1,1,ml211);
610 } else {
611 WARNING("msl(2,2) is NaN");
612 }
613
614 if (verbose_output) {
615 VERBOSE(" New msl(2,2) = " << ml211 << ", new MSvmL = " << get_MSvmL());
616 }
617}
618
619/**
620 * Determines soft-breaking right-handed smuon mass parameter from one
621 * smuon pole mass.
622 *
623 * @param precision_goal precision goal of iteration
624 * @param max_iterations maximum number of iterations
625 */
626void MSSMNoFV_onshell::convert_me2(
627 double precision_goal,
628 unsigned max_iterations)
629{
630 double precision = convert_me2_fpi(precision_goal, max_iterations);
631
632 if (precision > precision_goal) {
633 precision = convert_me2_root(precision_goal, max_iterations);
634 }
635
636 if (precision > precision_goal) {
638 } else {
640 }
641}
642
643/**
644 * Determines soft-breaking right-handed smuon mass parameter from one
645 * smuon pole mass. The function uses a one-dimensional root-finding
646 * algorithm.
647 *
648 * @param precision_goal precision goal for the root finding algorithm
649 * @param max_iterations maximum number of iterations
650 * @return achieved precision
651 */
652double MSSMNoFV_onshell::convert_me2_root_modify(
653 double precision_goal,
654 unsigned max_iterations)
655{
656 class Difference_MSm {
657 public:
658 explicit Difference_MSm(const MSSMNoFV_onshell& model_)
659 : model(model_) {}
660
661 double operator()(double me211) {
662 model.set_me2(1,1,me211);
663 model.calculate_MSm();
664
665 Eigen::Array<double,2,1> MSm_pole(model.get_physical().MSm);
666 std::sort(MSm_pole.data(), MSm_pole.data() + MSm_pole.size());
667 const int right_index = detail::find_right_like_smuon(model.get_ZM());
668
669 return model.get_MSm(right_index) - MSm_pole(right_index);
670 }
671 private:
672 MSSMNoFV_onshell model;
673 };
674
675 boost::uintmax_t it = max_iterations;
676
677 // stopping criterion, given two brackets a, b
678 auto Stop_crit = [precision_goal](double a, double b) -> bool {
680 };
681
682 if (verbose_output) {
683 VERBOSE("Converting mse(2,2) to on-shell scheme with root finder ...");
684 }
685
686 // initial guess for the brackets of me2(1,1)
687 const double initial_bracket = sqr(1e3 * get_MSm().cwiseAbs().maxCoeff());
688
689 // find the root
690 try {
691 const std::pair<double,double> root = boost::math::tools::toms748_solve(
693 set_me2(1, 1, 0.5*(root.first + root.second));
694 } catch (const std::exception& e) {
695 if (verbose_output) {
696 VERBOSE(" DR-bar to on-shell conversion for mse failed with"
697 " root finder: " << e.what());
698 }
699 }
700
702
703 const double precision = std::abs(Difference_MSm(*this)(get_me2(1,1)));
704
705 if (verbose_output) {
706 if (it >= max_iterations) {
707 VERBOSE(
708 " DR-bar to on-shell conversion for mse did not converge with"
709 " root finder (reached absolute accuracy: " << precision <<
710 " GeV, accuracy goal: " << precision_goal <<
711 ", max. iterations: " << max_iterations << ")");
712 }
713 VERBOSE(" Achieved absolute accuracy: " << precision << " GeV");
714 }
715
716 return precision;
717}
718
719/**
720 * Determines soft-breaking right-handed smuon mass parameter from one
721 * smuon pole mass. The function uses a one-dimensional root-finding
722 * algorithm.
723 *
724 * If a NaN appears during the FPI, the function resets the
725 * soft-breaking right-handed smuon mass parameter to the initial
726 * value and returns the maximum double.
727 *
728 * @param precision_goal precision goal for the root finding algorithm
729 * @param max_iterations maximum number of iterations
730 * @return achieved precision
731 */
732double MSSMNoFV_onshell::convert_me2_root(
733 double precision_goal,
734 unsigned max_iterations)
735{
736 const double me2_save = get_me2(1,1);
737 const double precision = convert_me2_root_modify(precision_goal, max_iterations);
738
739 if (!std::isfinite(precision) ||
740 !std::isfinite(get_me2(1,1)) ||
741 !get_MSm().allFinite() ||
742 !get_ZM().allFinite()) {
743 // reset
744 set_me2(1,1,me2_save);
746
747 return std::numeric_limits<double>::max();
748 }
749
750 return precision;
751}
752
753/**
754 * Determines soft-breaking right-handed smuon mass parameter from one
755 * smuon pole mass. The function uses a fixed-point iteration.
756 *
757 * @param precision_goal precision goal of iteration
758 * @param max_iterations maximum number of iterations
759 * @return achieved precision
760 */
761double MSSMNoFV_onshell::convert_me2_fpi_modify(
762 double precision_goal,
763 unsigned max_iterations)
764{
765 // sorted pole masses
766 Eigen::Array<double,2,1> MSm_pole_sorted(get_physical().MSm);
767 std::sort(MSm_pole_sorted.data(),
768 MSm_pole_sorted.data() + MSm_pole_sorted.size());
769
770 Eigen::Array<double,2,1> MSm_goal(MSm_pole_sorted);
771
773
774 if (verbose_output) {
775 VERBOSE("Converting mse(2,2) to on-shell scheme with FPI ...\n"
776 " Goal: MSm(" << right_index << ") = "
778 }
779
780 auto calc_precision = [&MSm_goal, this] (unsigned idx) {
781 return std::abs(get_MSm(idx) - MSm_goal(idx));
782 };
783
784 double precision = calc_precision(right_index);
785 unsigned it = 0;
786
787 while (precision > precision_goal && it < max_iterations) {
788 const Eigen::Matrix<double,2,2> ZM(get_ZM()); // smuon mixing matrix
789 const Eigen::Matrix<double,2,2> M(
790 ZM.adjoint() * MSm_goal.square().matrix().asDiagonal() * ZM);
791
792 const double vd2 = sqr(get_vd());
793 const double vu2 = sqr(get_vu());
794 const double g12 = sqr(get_g1());
795 const double ymu2 = std::norm(Ye(1,1));
796
797 const double me211 = M(1,1)
798 - (0.5*ymu2*vd2 - 0.15*g12*vd2 + 0.15*g12*vu2);
799
800 if (std::isfinite(me211)) {
801 set_me2(1,1,me211);
803 } else {
804 WARNING("mse2(2,2) is NaN");
805 break;
806 }
807
808 if (!std::isfinite(me211) || !get_MSm().allFinite() || !get_ZM().allFinite()) {
809 if (verbose_output) {
810 VERBOSE(" NaN appearing in DR-bar to on-shell conversion"
811 " for mse with FPI:\n"
812 " mse2(2,2) = " << me211 <<
813 ", MSm = " << pretty_print(get_MSm().transpose()) <<
814 ", ZM = " << pretty_print(get_ZM()));
815 }
816 return std::numeric_limits<double>::max();
817 }
818
820
821 MSm_goal = get_MSm();
823
824 const double old_precision = precision;
825 precision = calc_precision(right_index);
826
827 if (precision >= old_precision) {
828 if (verbose_output) {
829 VERBOSE(" No improvement in last iteration step, stopping iteration ...");
830 }
831 break;
832 }
833
834 if (verbose_output) {
835 VERBOSE(" Iteration " << it << ": mse(2,2) = "
836 << signed_abs_sqrt(me211) << ", MSm(" << right_index
837 << ") = " << get_MSm(right_index)
838 << ", accuracy = " << precision);
839 }
840
841 it++;
842 }
843
844 if (verbose_output) {
845 if (precision > precision_goal) {
846 VERBOSE(
847 " DR-bar to on-shell conversion for mse did not converge with"
848 " FPI (reached absolute accuracy: " << precision <<
849 " GeV, accuracy goal: " << precision_goal <<
850 ", max. iterations: " << max_iterations << ")");
851 }
852 VERBOSE(" Achieved absolute accuracy: " << precision << " GeV");
853 }
854
855 return precision;
856}
857
858/**
859 * Determines soft-breaking right-handed smuon mass parameter from one
860 * smuon pole mass. The function uses a fixed-point iteration.
861 *
862 * If a NaN appears during the FPI, the function resets the
863 * soft-breaking right-handed smuon mass parameter to the initial
864 * value and returns the maximum double.
865 *
866 * @param precision_goal precision goal of iteration
867 * @param max_iterations maximum number of iterations
868 * @return achieved precision
869 */
870double MSSMNoFV_onshell::convert_me2_fpi(
871 double precision_goal,
872 unsigned max_iterations)
873{
874 const double me2_save = get_me2(1,1);
875 const double precision = convert_me2_fpi_modify(precision_goal, max_iterations);
876
877 if (!std::isfinite(precision) ||
878 !std::isfinite(get_me2(1,1)) ||
879 !get_MSm().allFinite() ||
880 !get_ZM().allFinite()) {
881 // reset
882 set_me2(1,1,me2_save);
884
885 return std::numeric_limits<double>::max();
886 }
887
888 return precision;
889}
890
891std::ostream& operator<<(std::ostream& os, const MSSMNoFV_onshell& model)
892{
893 auto sas = [] (double x) { return gm2calc::signed_abs_sqrt(x); };
894
895 Eigen::Array<double,3,1> yd_non_res;
896 yd_non_res << (root2 * model.get_MD() / model.get_vd()),
897 (root2 * model.get_MS() / model.get_vd()),
898 (root2 * model.get_MB() / model.get_vd());
899
900 Eigen::Array<double,3,1> ye_non_res;
901 ye_non_res << (root2 * model.get_ME() / model.get_vd()),
902 (root2 * model.get_MM() / model.get_vd()),
903 (root2 * model.get_ML() / model.get_vd());
904
905 os <<
906 "===============================\n"
907 " GM2Calc masses and parameters \n"
908 "===============================\n"
909 "1/alpha(MZ) = " << 1./calculate_alpha(model.get_EL()) << '\n' <<
910 "1/alpha(0) = " << 1./calculate_alpha(model.get_EL0()) << '\n' <<
911 "alpha_s(MZ) = " << calculate_alpha(model.get_g3()) << '\n' <<
912 "MM pole = " << model.get_MM() << " GeV\n" <<
913 "MT = " << model.get_MT() << " GeV\n" <<
914 "mb(mb) MS-bar = " << model.get_MBMB() << " GeV\n" <<
915 "mb(MZ) DR-bar = " << model.get_MB() << " GeV\n" <<
916 "MTau = " << model.get_ML() << " GeV\n" <<
917 "MW pole = " << model.get_MW() << " GeV\n" <<
918 "MZ pole = " << model.get_MZ() << " GeV\n" <<
919 "MSm pole = " << pretty_print(model.get_MSm().transpose()) << " GeV\n" <<
920 "USm pole = " << pretty_print(model.get_USm()) << '\n' <<
921 "MSvm pole = " << model.get_MSvmL() << " GeV\n" <<
922 "MSb = " << pretty_print(model.get_MSb().transpose()) << " GeV\n" <<
923 "USb = " << pretty_print(model.get_USb()) << '\n' <<
924 "MSt = " << pretty_print(model.get_MSt().transpose()) << " GeV\n" <<
925 "USt = " << pretty_print(model.get_USt()) << '\n' <<
926 "MStau = " << pretty_print(model.get_MStau().transpose()) << " GeV\n" <<
927 "UStau = " << pretty_print(model.get_UStau()) << '\n' <<
928 "MCha pole = " << pretty_print(model.get_MCha().transpose()) << " GeV\n" <<
929 "UM pole = " << pretty_print(model.get_UM()) << '\n' <<
930 "UP pole = " << pretty_print(model.get_UP()) << '\n' <<
931 "MChi pole = " << pretty_print(model.get_MChi().transpose()) << " GeV\n" <<
932 "ZN pole = {" << pretty_print(model.get_ZN().row(0)) << ",\n" <<
933 " " << pretty_print(model.get_ZN().row(1)) << ",\n" <<
934 " " << pretty_print(model.get_ZN().row(2)) << ",\n" <<
935 " " << pretty_print(model.get_ZN().row(3)) << "}\n" <<
936 "MA0 = " << model.get_MA0() << " GeV\n" <<
937 "MH = " << pretty_print(model.get_Mhh().transpose()) << " GeV\n" <<
938 "tan(beta) DR-bar = " << model.get_TB() << '\n' <<
939 "yu = " << pretty_print(model.get_Yu().diagonal().transpose()) << '\n' <<
940 "yd resummed = " << pretty_print(model.get_Yd().diagonal().transpose()) << '\n' <<
941 "ye resummed = " << pretty_print(model.get_Ye().diagonal().transpose()) << '\n' <<
942 "yd non res. = " << pretty_print(yd_non_res.transpose()) << '\n' <<
943 "ye non res. = " << pretty_print(ye_non_res.transpose()) << '\n' <<
944 "Mu on-shell = " << model.get_Mu() << " GeV\n" <<
945 "M1 on-shell = " << model.get_MassB() << " GeV\n" <<
946 "M2 on-shell = " << model.get_MassWB() << " GeV\n" <<
947 "M3 = " << model.get_MassG() << " GeV\n" <<
948 "msl on-shell = " << pretty_print(model.get_ml2().diagonal().transpose().unaryExpr(sas)) << " GeV\n" <<
949 "mse on-shell = " << pretty_print(model.get_me2().diagonal().transpose().unaryExpr(sas)) << " GeV\n" <<
950 "msq = " << pretty_print(model.get_mq2().diagonal().transpose().unaryExpr(sas)) << " GeV\n" <<
951 "msu = " << pretty_print(model.get_mu2().diagonal().transpose().unaryExpr(sas)) << " GeV\n" <<
952 "msd = " << pretty_print(model.get_md2().diagonal().transpose().unaryExpr(sas)) << " GeV\n" <<
953 "Au = " << pretty_print(model.get_Au().diagonal().transpose()) << " GeV\n" <<
954 "Ad = " << pretty_print(model.get_Ad().diagonal().transpose()) << " GeV\n" <<
955 "Ae DR-bar = " << pretty_print(model.get_Ae().diagonal().transpose()) << " GeV\n" <<
956 "ren. scale = " << model.get_scale() << " GeV\n"
957 ;
958
959 return os;
960}
961
962} // namespace gm2calc
#define WARN_OR_THROW_IF(cond, msg)
#define COPY_IF_ZERO_1(m, z)
#define COPY_IF_ZERO_2(m, u, v)
#define COPY_IF_ZERO_0(m)
#define WARN_OR_THROW_IF_ZERO(mass, msg)
const Eigen::Matrix< std::complex< double >, 4, 4 > & get_ZN() const
const Eigen::Matrix< std::complex< double >, 2, 2 > & get_UM() const
void calculate_DRbar_masses()
routine which finds the DRbar mass eigenstates and mixings.
const Eigen::Array< double, 2, 1 > & get_MAh() const
const Eigen::Array< double, 4, 1 > & get_MChi() const
const MSSMNoFV_onshell_physical & get_physical() const
const Eigen::Matrix< std::complex< double >, 2, 2 > & get_UP() const
const Eigen::Array< double, 2, 1 > & get_MCha() const
const Eigen::Array< double, 2, 1 > & get_MSm() const
const Eigen::Matrix< double, 2, 2 > & get_ZM() const
const MSSMNoFV_onshell_problems & get_problems() const
const Eigen::Array< double, 2, 1 > & get_Mhh() const
void clear()
delete all problems and warnings
void flag_no_convergence_Mu_MassB_MassWB(double, unsigned)
const Eigen::Matrix< double, 3, 3 > & get_mq2() const
const Eigen::Matrix< double, 3, 3 > & get_mu2() const
const Eigen::Matrix< double, 3, 3 > & get_md2() const
const Eigen::Matrix< double, 3, 3 > & get_me2() const
void set_TYd(const Eigen::Matrix< double, 3, 3 > &TYd_)
const Eigen::Matrix< double, 3, 3 > & get_ml2() const
void set_ml2(const Eigen::Matrix< double, 3, 3 > &ml2_)
void set_TYu(const Eigen::Matrix< double, 3, 3 > &TYu_)
void set_me2(const Eigen::Matrix< double, 3, 3 > &me2_)
void set_TYe(const Eigen::Matrix< double, 3, 3 > &TYe_)
void set_Yu(const Eigen::Matrix< double, 3, 3 > &Yu_)
void set_Ye(const Eigen::Matrix< double, 3, 3 > &Ye_)
void set_Yd(const Eigen::Matrix< double, 3, 3 > &Yd_)
contains the MSSMNoFV parameters in the on-shell scheme
double get_TB() const
tan(beta) DR-bar
double get_MM() const
returns muon pole mass
double get_ME() const
returns electron mass
double get_MW() const
returns W boson pole mass
double get_MA0() const
returns CP-odd Higgs mass
double get_MS() const
returns strange-quark mass
double get_MU() const
returns up-quark mass
double get_vev() const
Vacuum expectation value v.
double get_MT() const
returns top-quark mass
double get_MB() const
returns mb(MZ) DR-bar
double get_ML() const
returns tau mass
double get_MC() const
returns charm-quark mass
double get_MZ() const
returns Z boson pole mass
double get_EL() const
electromagnetic gauge coupling at MZ w/o hadronic corrections
double get_MD() const
returns down-quark mass
double get_MBMB() const
returns mb(mb) MS-bar
#define VERBOSE(message)
Definition gm2_log.hpp:27
#define WARNING(message)
Definition gm2_log.hpp:30
double v
double tanb
struct MSSMNoFV_onshell MSSMNoFV_onshell
unsigned find_bino_like_neutralino(const Eigen::MatrixBase< Derived > &ZN)
Returns index of most bino-like neutralino.
unsigned find_right_like_smuon(const Eigen::MatrixBase< Derived > &ZM)
Returns index of most right-handed smuon.
T sqr(T x) noexcept
returns number squared
double delta_bottom_correction(const MSSMNoFV_onshell &model)
Returns the corrections from arxiv:0901.2065, Eq (103) and Eqs (31)-(35)
constexpr double MM
constexpr double MW
constexpr double MT
constexpr double MBMB
constexpr double MZ
void svd_eigen(const Eigen::Matrix< Scalar, M, N > &m, Eigen::Array< Real,(((M)<(N)) ?(M) :(N)), 1 > &s, Eigen::Matrix< Scalar, M, M > *u, Eigen::Matrix< Scalar, N, N > *vh)
constexpr double ALPHA_EM_MZ
bool is_zero(const Eigen::ArrayBase< Derived > &a, double eps)
double delta_tau_correction(const MSSMNoFV_onshell &model)
Calculates using delta_down_lepton_correction()
std::ostream & operator<<(std::ostream &os, const MSSMNoFV_onshell &model)
streaming operator
constexpr double ALPHA_EM_THOMPSON
double calculate_mb_SM5_DRbar(double mb_mb, double alpha_s, double scale)
Calculates mb(Q) in the DR-bar scheme in the SM w/ 5 active quark flavours using the approach describ...
Definition gm2_mf.cpp:202
constexpr double ME
double signed_abs_sqrt(double x) noexcept
returns square root of absolute of number, times sign
constexpr double ALPHA_S_MZ
bool is_equal(const Eigen::ArrayBase< Derived > &a, const Eigen::ArrayBase< Derived > &b, double precision_goal)
double delta_mu_correction(const MSSMNoFV_onshell &model)
Calculates using delta_down_lepton_correction()
constexpr double ML