TransitionListener 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. transitionlistener/__init__.py +21 -0
  2. transitionlistener/bubbledynamics.py +2250 -0
  3. transitionlistener/bubbledynamics_fixedstep.py +2929 -0
  4. transitionlistener/check_installation.py +309 -0
  5. transitionlistener/ckm.py +91 -0
  6. transitionlistener/colors.py +288 -0
  7. transitionlistener/config.py +185 -0
  8. transitionlistener/constants.py +64 -0
  9. transitionlistener/counterterms/__init__.py +230 -0
  10. transitionlistener/counterterms/cw.py +298 -0
  11. transitionlistener/counterterms/tensors.py +343 -0
  12. transitionlistener/counterterms/twohdm.py +520 -0
  13. transitionlistener/counterterms/twohdm_solver.py +374 -0
  14. transitionlistener/errors.py +315 -0
  15. transitionlistener/examples/bp_et.yaml +64 -0
  16. transitionlistener/examples/bp_lisa.yaml +70 -0
  17. transitionlistener/examples/bp_muares.yaml +69 -0
  18. transitionlistener/examples/bp_pta.yaml +64 -0
  19. transitionlistener/examples/example_dark_photon.yaml +73 -0
  20. transitionlistener/examples/example_grid.yaml +55 -0
  21. transitionlistener/examples/example_line.yaml +51 -0
  22. transitionlistener/examples/example_point.yaml +73 -0
  23. transitionlistener/examples/example_random_conformal.yaml +42 -0
  24. transitionlistener/examples/example_ultranest.yaml +39 -0
  25. transitionlistener/finiteT.py +468 -0
  26. transitionlistener/generic_potential.py +1521 -0
  27. transitionlistener/gridplots.py +592 -0
  28. transitionlistener/gwfopt.py +604 -0
  29. transitionlistener/helper_functions.py +843 -0
  30. transitionlistener/hydrodynamics.py +647 -0
  31. transitionlistener/interface/__init__.py +95 -0
  32. transitionlistener/interface/check.py +51 -0
  33. transitionlistener/interface/cli.py +211 -0
  34. transitionlistener/interface/config_loader.py +264 -0
  35. transitionlistener/interface/logging_utils.py +30 -0
  36. transitionlistener/interface/output_schema.py +296 -0
  37. transitionlistener/interface/pipeline.py +300 -0
  38. transitionlistener/interface/samplers.py +565 -0
  39. transitionlistener/interface/scans.py +468 -0
  40. transitionlistener/interface/single_point.py +581 -0
  41. transitionlistener/interface/state.py +61 -0
  42. transitionlistener/lineplots.py +597 -0
  43. transitionlistener/logo/TL-logo_large.png +0 -0
  44. transitionlistener/logo/TL-logo_small.png +0 -0
  45. transitionlistener/models/TL_2HDM.py +512 -0
  46. transitionlistener/models/TL_conformal_dark_u1.py +202 -0
  47. transitionlistener/models/TL_dark_U1.py +198 -0
  48. transitionlistener/models/TL_dark_U1_g_parameterization.py +198 -0
  49. transitionlistener/models/TL_dark_flipflop.py +274 -0
  50. transitionlistener/models/templatePotential.py +260 -0
  51. transitionlistener/nucleation.py +412 -0
  52. transitionlistener/observability.py +790 -0
  53. transitionlistener/particles.py +436 -0
  54. transitionlistener/pathDeformation.py +1462 -0
  55. transitionlistener/percolation_adaptive_gridbuilders.py +1385 -0
  56. transitionlistener/percolation_adaptive_rate.py +1049 -0
  57. transitionlistener/percolation_adaptivestepsize.py +1632 -0
  58. transitionlistener/percolation_fixedstepsize.py +618 -0
  59. transitionlistener/phases.py +1499 -0
  60. transitionlistener/plot_settings.py +121 -0
  61. transitionlistener/plots.py +1781 -0
  62. transitionlistener/runtime_options.py +278 -0
  63. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/bandwidths.npy +0 -0
  64. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/density.npy +0 -0
  65. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/freqs.npy +0 -0
  66. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log.txt +16 -0
  67. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log10rhogrid.npy +0 -0
  68. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log10rholabels.txt +30 -0
  69. transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/pulsar_list.txt +1 -0
  70. transitionlistener/tab_data/HLV-O2-PLI.csv +82 -0
  71. transitionlistener/tab_data/HLV-O2-noise.csv +83 -0
  72. transitionlistener/tab_data/HLVK-design-PLI.csv +61 -0
  73. transitionlistener/tab_data/HLVK-design-noise.csv +83 -0
  74. transitionlistener/tab_data/NG15_PLI_hc.csv +31 -0
  75. transitionlistener/tab_data/NG15_noise_hc.csv +56 -0
  76. transitionlistener/tab_data/PLI-dataset.csv +327 -0
  77. transitionlistener/tab_data/energydensities.dat +1001 -0
  78. transitionlistener/tab_data/finiteT_b.dat.txt +1999 -0
  79. transitionlistener/tab_data/finiteT_f.dat.txt +1000 -0
  80. transitionlistener/tab_data/geff_SM.dat +10009 -0
  81. transitionlistener/tab_data/muAres_f_Hz_PLI_h2OmegaGW.csv +131 -0
  82. transitionlistener/tab_data/muAres_f_Hz_h2Omega_noise.csv +99 -0
  83. transitionlistener/tab_data/noise-dataset.csv +327 -0
  84. transitionlistener/tab_data/numberdensities.dat +1001 -0
  85. transitionlistener/tab_data/pressures.dat +1001 -0
  86. transitionlistener/thermodynamics.py +686 -0
  87. transitionlistener/transitionObservables.py +1199 -0
  88. transitionlistener/transitionObservables_fixedstep.py +976 -0
  89. transitionlistener/transitions.py +1000 -0
  90. transitionlistener/tunneling1D.py +910 -0
  91. transitionlistener-2.0.0.dist-info/METADATA +817 -0
  92. transitionlistener-2.0.0.dist-info/RECORD +95 -0
  93. transitionlistener-2.0.0.dist-info/WHEEL +4 -0
  94. transitionlistener-2.0.0.dist-info/entry_points.txt +2 -0
  95. transitionlistener-2.0.0.dist-info/licenses/LICENSE.txt +674 -0
@@ -0,0 +1,512 @@
1
+ """
2
+ Two-Higgs-doublet model (2HDM) with internal counterterm calculation.
3
+
4
+ The implementation mirrors the renormalisation prescription used in BSMPT for
5
+ the CP-conserving 2HDM (ClassPotentialR2HDM).
6
+
7
+ Part of TransitionListener v2.0
8
+ Documentation: https://tasillo.de/TransitionListener/
9
+
10
+ Authors:
11
+ Jonas Matuszak <jonas.matuszak@kit.edu>
12
+ Carlo Tasillo <carlo.tasillo@ific.uv.es>
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import numpy as np
18
+
19
+ from transitionlistener import config, errors, generic_potential
20
+ from transitionlistener.constants import SM_FERMION_MASSES_GEV, SM_GAUGE_MASSES_GEV
21
+ from transitionlistener.generic_potential import console as tl_console
22
+ from transitionlistener.helper_functions import eigenvalues_2x2
23
+ from transitionlistener.particles import (
24
+ GaugeBoson,
25
+ MassSpectrum,
26
+ Scalar,
27
+ Fermion,
28
+ Goldstone,
29
+ )
30
+ from transitionlistener.counterterms import CounterTerms
31
+ from transitionlistener.counterterms.twohdm_solver import compute_counterterms
32
+
33
+
34
+ class R2HDM(generic_potential.generic_potential):
35
+ """CP-conserving 2HDM with internally computed counterterms."""
36
+
37
+ _YUKAWA_TYPE_MAP = {
38
+ 1: "TypeI",
39
+ 2: "TypeII",
40
+ 3: "TypeLeptonSpecific",
41
+ 4: "TypeFlipped",
42
+ }
43
+
44
+ model_parameters = {
45
+ "lambda1": {
46
+ "default": 0.6,
47
+ "plotname": r"$\lambda_1$",
48
+ "min": -4 * np.pi,
49
+ "max": 4 * np.pi,
50
+ },
51
+ "lambda2": {
52
+ "default": 0.6,
53
+ "plotname": r"$\lambda_2$",
54
+ "min": -4 * np.pi,
55
+ "max": 4 * np.pi,
56
+ },
57
+ "lambda3": {
58
+ "default": 0.1,
59
+ "plotname": r"$\lambda_3$",
60
+ "min": -4 * np.pi,
61
+ "max": 4 * np.pi,
62
+ },
63
+ "lambda4": {
64
+ "default": -0.2,
65
+ "plotname": r"$\lambda_4$",
66
+ "min": -4 * np.pi,
67
+ "max": 4 * np.pi,
68
+ },
69
+ "lambda5": {
70
+ "default": 0.0,
71
+ "plotname": r"$\lambda_5$",
72
+ "min": -4 * np.pi,
73
+ "max": 4 * np.pi,
74
+ },
75
+ "m12_sq_GeV2": {
76
+ "default": 200.0**2,
77
+ "plotname": r"$m_{12}^2$ [GeV$^2$]",
78
+ "min": -np.inf,
79
+ "max": np.inf,
80
+ },
81
+ "tan_beta": {
82
+ "default": 2.0,
83
+ "plotname": r"$\tan\beta$",
84
+ "min": 0.05,
85
+ "max": 50.0,
86
+ },
87
+ "yukawa_type": {
88
+ "default": 2,
89
+ "plotname": r"Type",
90
+ "min": 1,
91
+ "max": 4,
92
+ },
93
+ "v_GeV": {
94
+ "default": 246.21965079413735,
95
+ "plotname": r"$v$ [GeV]",
96
+ "min": 0,
97
+ "max": np.inf,
98
+ },
99
+ }
100
+
101
+ def init(self, inputparam_dict, verbose: bool = True): # noqa: D401
102
+ self.mp = self.set_modelparams(inputparam_dict)
103
+
104
+ self.lambda1 = float(self.mp["lambda1"]["value"])
105
+ self.lambda2 = float(self.mp["lambda2"]["value"])
106
+ self.lambda3 = float(self.mp["lambda3"]["value"])
107
+ self.lambda4 = float(self.mp["lambda4"]["value"])
108
+ self.lambda5 = float(self.mp["lambda5"]["value"])
109
+ self.m12_sq_GeV2 = float(self.mp["m12_sq_GeV2"]["value"])
110
+ self.tan_beta = float(self.mp["tan_beta"]["value"])
111
+ self.yukawa_type = int(round(float(self.mp["yukawa_type"]["value"])))
112
+ self.v_GeV = float(self.mp["v_GeV"]["value"])
113
+
114
+ self.retrieved_input = np.array(
115
+ [
116
+ self.lambda1,
117
+ self.lambda2,
118
+ self.lambda3,
119
+ self.lambda4,
120
+ self.lambda5,
121
+ self.m12_sq_GeV2,
122
+ self.tan_beta,
123
+ self.yukawa_type,
124
+ self.v_GeV,
125
+ ],
126
+ dtype=float,
127
+ )
128
+
129
+ self.Ndim = 2
130
+ self.verbose = verbose
131
+
132
+ self.daisy = "ArnoldEspinosa"
133
+ # The 2HDM is the only model in v2.0 where the natural internal scale
134
+ # coincides with the SM electroweak vev, so we keep v_stable and the
135
+ # conversion factor in their physical units rather than rescaling.
136
+ self.v_stable = 246.21965079413735
137
+ self.v = self.v_stable
138
+ self.conversionFactor = 1.0
139
+ self.deriv_order = max(self.deriv_order, 4)
140
+
141
+ if not (1 <= self.yukawa_type <= 4):
142
+ raise errors.InitPotentialError(
143
+ f"Invalid Yukawa type {self.yukawa_type}. Expected integer in [1, 4]."
144
+ )
145
+ if np.isclose(self.tan_beta, 0.0):
146
+ raise errors.InitPotentialError("tan_beta may not vanish in the 2HDM.")
147
+
148
+ cos_beta = 1.0 / np.sqrt(1.0 + self.tan_beta**2)
149
+ sin_beta = self.tan_beta * cos_beta
150
+ if self.tan_beta < 0.0:
151
+ sin_beta = -abs(sin_beta)
152
+ self.cos_beta = cos_beta
153
+ self.sin_beta = sin_beta
154
+ self.beta = np.arctan(self.tan_beta)
155
+
156
+ self.v1 = self.v * self.cos_beta
157
+ self.v2 = self.v * self.sin_beta
158
+ self.v1_GeV = self.v1 * self.conversionFactor
159
+ self.v2_GeV = self.v2 * self.conversionFactor
160
+
161
+ self.m12_sq = self.m12_sq_GeV2 / self.conversionFactor**2
162
+
163
+ C_CosBetaSquared = 1.0 / (1 + self.tan_beta * self.tan_beta)
164
+ C_CosBeta = np.sqrt(C_CosBetaSquared)
165
+ C_SinBetaSquared = self.tan_beta * self.tan_beta * C_CosBetaSquared
166
+ C_SinBeta = np.sqrt(C_SinBetaSquared)
167
+
168
+ if (self.tan_beta < 0):
169
+ C_SinBeta *= -1;
170
+
171
+ print("RealMMix = ", self.m12_sq)
172
+ print("TanBeta = ", self.tan_beta)
173
+ print("scale = ", self.v_stable)
174
+ print("L1 = ", self.lambda1)
175
+ print("L2 = ", self.lambda2)
176
+ print("L3 = ", self.lambda3)
177
+ print("L4 = ", self.lambda4)
178
+ print("L5 = ", self.lambda5)
179
+
180
+ self.m11_sq = self.m12_sq * self.tan_beta - self.v_stable * self.v_stable * \
181
+ C_SinBetaSquared * (self.lambda4 + self.lambda5 + self.lambda3) / 0.2e1 - \
182
+ self.v_stable * self.v_stable * C_CosBetaSquared * self.lambda1 / 0.2e1
183
+ self.m22_sq = self.m12_sq * 1.0 / self.tan_beta - self.v_stable * self.v_stable * \
184
+ C_CosBetaSquared * (self.lambda4 + self.lambda5 + self.lambda3) / 0.2e1 - \
185
+ self.v_stable * self.v_stable * C_SinBetaSquared * self.lambda2 / 0.2e1
186
+
187
+ print("m11 = ", self.m11_sq)
188
+ print("m22 = ", self.m22_sq)
189
+
190
+ self.lambda345 = self.lambda3 + self.lambda4 + self.lambda5
191
+ self.lambda34m5 = self.lambda3 + self.lambda4 - self.lambda5
192
+ self.lambda45 = self.lambda4 + self.lambda5
193
+
194
+ # self.m11_sq = (
195
+ # self.m12_sq * self.tan_beta
196
+ # - 0.5 * self.lambda1 * self.v1 * self.v1
197
+ # - 0.5 * self.lambda345 * self.v2 * self.v2
198
+ # )
199
+ # self.m22_sq = (
200
+ # self.m12_sq / self.tan_beta
201
+ # - 0.5 * self.lambda2 * self.v2 * self.v2
202
+ # - 0.5 * self.lambda345 * self.v1 * self.v1
203
+ # )
204
+
205
+ # SM inputs (GeV)
206
+ self.mW_GeV = SM_GAUGE_MASSES_GEV["mW"]
207
+ self.mZ_GeV = SM_GAUGE_MASSES_GEV["mZ"]
208
+ self.mt_GeV = SM_FERMION_MASSES_GEV["m_t"]
209
+ self.mb_GeV = SM_FERMION_MASSES_GEV["m_b"]
210
+ self.mtau_GeV = SM_FERMION_MASSES_GEV["m_tau"]
211
+
212
+ self.g2 = 2.0 * self.mW_GeV / self.v_GeV
213
+ self.g1 = np.sqrt(4.0 * self.mZ_GeV**2 / self.v_GeV**2 - self.g2**2)
214
+
215
+ self.yt = self.mt_GeV / self.v2_GeV
216
+ self._bottom_uses_phi2 = self.yukawa_type in (1, 3)
217
+ self._lepton_uses_phi2 = self.yukawa_type in (1, 4)
218
+ v_bottom = self.v2_GeV if self._bottom_uses_phi2 else self.v1_GeV
219
+ v_lepton = self.v2_GeV if self._lepton_uses_phi2 else self.v1_GeV
220
+ self.yb = self.mb_GeV / v_bottom
221
+ self.ytau = self.mtau_GeV / v_lepton
222
+
223
+ coeff_gauge = 3.0 * (3.0 * self.g2**2 + self.g1**2)
224
+ ct = np.sqrt(2.0) * self.yt
225
+ cb = np.sqrt(2.0) * self.yb
226
+ self.CTempC1 = (
227
+ 12.0 * self.lambda1 + 8.0 * self.lambda3 + 4.0 * self.lambda4 + coeff_gauge
228
+ ) / 48.0
229
+ self.CTempC2 = (
230
+ 12.0 * self.lambda2
231
+ + 8.0 * self.lambda3
232
+ + 4.0 * self.lambda4
233
+ + coeff_gauge
234
+ + 12.0 * ct * ct
235
+ ) / 48.0
236
+ if self._bottom_uses_phi2:
237
+ self.CTempC2 += 12.0 * cb * cb / 48.0
238
+ else:
239
+ self.CTempC1 += 12.0 * cb * cb / 48.0
240
+
241
+ self.X0 = np.array([self.v1, self.v2])
242
+ self.renormScaleSq = self.v1 * self.v1 + self.v2 * self.v2
243
+ self.mass_spectrum = self._build_mass_spectrum()
244
+
245
+ counterterms = self._initialize_counterterms()
246
+ self.dlambda1 = counterterms.dlambda1
247
+ self.dlambda2 = counterterms.dlambda2
248
+ self.dlambda3 = counterterms.dlambda3
249
+ self.dlambda4 = counterterms.dlambda4
250
+ self.dlambda5 = counterterms.dlambda5
251
+ self.dm11_sq = counterterms.dm11_sq
252
+ self.dm22_sq = counterterms.dm22_sq
253
+ self.dm12_sq = counterterms.dm12_sq
254
+
255
+ inv_cf_sq = 1.0 / (self.conversionFactor * self.conversionFactor)
256
+ self.dm11_sq_GeV2 = self.dm11_sq * inv_cf_sq
257
+ self.dm22_sq_GeV2 = self.dm22_sq * inv_cf_sq
258
+ self.dm12_sq_GeV2 = self.dm12_sq * inv_cf_sq
259
+
260
+ mh_sq, mH_sq = self._cp_even_eigenvalues(self.v1, self.v2, 0.0)
261
+ _, mA_sq = self._cp_odd_eigenvalues(self.v1, self.v2, 0.0)
262
+ _, mHpm_sq = self._charged_eigenvalues(self.v1, self.v2, 0.0)
263
+
264
+ self.derived_parameters = {
265
+ "v1_GeV": self.v1_GeV,
266
+ "v2_GeV": self.v2_GeV,
267
+ "m11_sq_GeV2": self.m11_sq * self.conversionFactor**2,
268
+ "m22_sq_GeV2": self.m22_sq * self.conversionFactor**2,
269
+ "m12_sq_GeV2": self.m12_sq_GeV2,
270
+ "mh_GeV": np.sqrt(max(mh_sq, 0.0)) * self.conversionFactor,
271
+ "mH_GeV": np.sqrt(max(mH_sq, 0.0)) * self.conversionFactor,
272
+ "mA_GeV": np.sqrt(max(mA_sq, 0.0)) * self.conversionFactor,
273
+ "mHp_GeV": np.sqrt(max(mHpm_sq, 0.0)) * self.conversionFactor,
274
+ "delta_m11_sq_GeV2": self.dm11_sq_GeV2,
275
+ "delta_m22_sq_GeV2": self.dm22_sq_GeV2,
276
+ "delta_m12_sq_GeV2": self.dm12_sq_GeV2,
277
+ "delta_lambda1": self.dlambda1,
278
+ "delta_lambda2": self.dlambda2,
279
+ "delta_lambda3": self.dlambda3,
280
+ "delta_lambda4": self.dlambda4,
281
+ "delta_lambda5": self.dlambda5,
282
+ }
283
+
284
+ # ------------------------------------------------------------------
285
+ # Counterterm determination
286
+ # ------------------------------------------------------------------
287
+ def _initialize_counterterms(self) -> CounterTerms:
288
+ (
289
+ counterterms,
290
+ grad_internal,
291
+ H_internal,
292
+ residual_internal,
293
+ ) = compute_counterterms(self)
294
+ residual_norm = float(np.max(np.abs(residual_internal)))
295
+ if residual_norm > 1e-6:
296
+ tl_console.print(
297
+ "[yellow]Warning: Renormalised Coleman–Weinberg conditions "
298
+ f"deviate by {residual_norm:.3e} in internal units "
299
+ "(expected to be near zero).[/yellow]"
300
+ )
301
+ self._cw_gradient = grad_internal
302
+ self._cw_hessian = H_internal
303
+ self._cw_residual = residual_internal
304
+ return counterterms
305
+
306
+ # ------------------------------------------------------------------
307
+ # Thermal mass shifts and eigenvalues in the 2D field space
308
+ # ------------------------------------------------------------------
309
+ def _scalar_daisy_shifts(self, T):
310
+ if self.daisy not in ("ArnoldEspinosa", "Parwani"):
311
+ return 0.0, 0.0
312
+ T_arr = np.asarray(T, dtype=float)
313
+ T2 = T_arr * T_arr
314
+ Pi1 = self.CTempC1 * T2
315
+ Pi2 = self.CTempC2 * T2
316
+ return Pi1, Pi2
317
+
318
+ def _scalar_mass_entries(self, phi1, phi2, sector):
319
+ phi1 = np.asarray(phi1, dtype=float)
320
+ phi2 = np.asarray(phi2, dtype=float)
321
+ if sector == "cp_even":
322
+ a = (
323
+ self.m11_sq
324
+ + 1.5 * self.lambda1 * phi1**2
325
+ + 0.5 * self.lambda345 * phi2**2
326
+ )
327
+ c = (
328
+ self.m22_sq
329
+ + 1.5 * self.lambda2 * phi2**2
330
+ + 0.5 * self.lambda345 * phi1**2
331
+ )
332
+ b = -self.m12_sq + self.lambda345 * phi1 * phi2
333
+ elif sector == "cp_odd":
334
+ a = (
335
+ self.m11_sq
336
+ + 0.5 * self.lambda1 * phi1**2
337
+ + 0.5 * self.lambda34m5 * phi2**2
338
+ )
339
+ c = (
340
+ self.m22_sq
341
+ + 0.5 * self.lambda2 * phi2**2
342
+ + 0.5 * self.lambda34m5 * phi1**2
343
+ )
344
+ b = -self.m12_sq + self.lambda5 * phi1 * phi2
345
+ elif sector == "charged":
346
+ a = (
347
+ self.m11_sq
348
+ + 0.5 * self.lambda1 * phi1**2
349
+ + 0.5 * self.lambda3 * phi2**2
350
+ )
351
+ c = (
352
+ self.m22_sq
353
+ + 0.5 * self.lambda2 * phi2**2
354
+ + 0.5 * self.lambda3 * phi1**2
355
+ )
356
+ b = -self.m12_sq + 0.5 * self.lambda45 * phi1 * phi2
357
+ else:
358
+ raise ValueError(f"Unknown scalar sector '{sector}'.")
359
+ return a, b, c
360
+
361
+ def _cp_even_eigenvalues(self, phi1, phi2, T):
362
+ a, b, c = self._scalar_mass_entries(phi1, phi2, "cp_even")
363
+ Pi1, Pi2 = self._scalar_daisy_shifts(T)
364
+ return eigenvalues_2x2(a + Pi1, b, c + Pi2)
365
+
366
+ def _cp_odd_eigenvalues(self, phi1, phi2, T):
367
+ a, b, c = self._scalar_mass_entries(phi1, phi2, "cp_odd")
368
+ Pi1, Pi2 = self._scalar_daisy_shifts(T)
369
+ return eigenvalues_2x2(a + Pi1, b, c + Pi2)
370
+
371
+ def _charged_eigenvalues(self, phi1, phi2, T):
372
+ a, b, c = self._scalar_mass_entries(phi1, phi2, "charged")
373
+ Pi1, Pi2 = self._scalar_daisy_shifts(T)
374
+ return eigenvalues_2x2(a + Pi1, b, c + Pi2)
375
+
376
+ # ------------------------------------------------------------------
377
+ # Potentials used by TransitionListener
378
+ # ------------------------------------------------------------------
379
+ def V0(self, X):
380
+ X = np.asarray(X, dtype=float)
381
+ phi1 = X[..., 0]
382
+ phi2 = X[..., 1]
383
+ tree = 0.5 * self.m11_sq * phi1**2 + 0.5 * self.m22_sq * phi2**2
384
+ tree -= self.m12_sq * phi1 * phi2
385
+ tree += 0.125 * self.lambda1 * phi1**4
386
+ tree += 0.125 * self.lambda2 * phi2**4
387
+ tree += 0.25 * self.lambda345 * phi1**2 * phi2**2
388
+ return tree
389
+
390
+ def Vct(self, X):
391
+ X = np.asarray(X, dtype=float)
392
+ phi1 = X[..., 0]
393
+ phi2 = X[..., 1]
394
+ counter = 0.5 * self.dm11_sq * phi1**2 + 0.5 * self.dm22_sq * phi2**2
395
+ counter -= self.dm12_sq * phi1 * phi2
396
+ counter += 0.125 * self.dlambda1 * phi1**4
397
+ counter += 0.125 * self.dlambda2 * phi2**4
398
+ counter += (
399
+ 0.25 * (self.dlambda3 + self.dlambda4 + self.dlambda5) * phi1**2 * phi2**2
400
+ )
401
+ return counter
402
+
403
+ # ------------------------------------------------------------------
404
+ # Spectrum construction (2D field space)
405
+ # ------------------------------------------------------------------
406
+ def _build_mass_spectrum(self) -> MassSpectrum:
407
+
408
+ def boson_mass_function(X, T):
409
+ X = np.asarray(X)
410
+ T2 = T * T
411
+ phi1 = X[..., 0]
412
+ phi2 = X[..., 1]
413
+ phi_sq = phi1**2 + phi2**2
414
+
415
+ Nbosons = 12 # How many entries?
416
+ M2 = np.empty(phi1.shape + (Nbosons,))
417
+
418
+ # Scalars and Goldstones
419
+ cp_even_light, cp_even_heavy = self._cp_even_eigenvalues(phi1, phi2, T)
420
+ cp_odd_small, cp_odd_large = self._cp_odd_eigenvalues(phi1, phi2, T)
421
+ charged_small, charged_large = self._charged_eigenvalues(phi1, phi2, T)
422
+
423
+ M2[..., 0] = cp_even_light
424
+ M2[..., 1] = cp_even_heavy
425
+ M2[..., 2] = cp_odd_large
426
+ M2[..., 3] = cp_odd_small
427
+ M2[..., 4] = charged_large
428
+ M2[..., 5] = charged_small
429
+
430
+ # Gauge bosons
431
+ Pi_WL = 2 * self.g2**2 * T2
432
+ Pi_BL = 2 * self.g1**2 * T2
433
+ a = 0.25 * self.g2**2 * phi_sq + Pi_WL
434
+ b = -0.25 * self.g1 * self.g2 * phi_sq
435
+ c = 0.25 * self.g1**2 * phi_sq + Pi_BL
436
+ discr = np.sqrt(np.maximum(a**2 + 4.0 * b**2 - 2.0 * a * c + c**2, 0.0))
437
+ mZ2 = 0.25 * (self.g1**2 + self.g2**2) * phi_sq
438
+ mZ2L = 0.5 * (a + c + discr)
439
+ mA2L = 0.5 * (a + c - discr)
440
+ mA2 = 0.5 * (a + c - discr)
441
+ mW2 = 0.25 * self.g2**2 * phi_sq
442
+ mW2L = mW2 + Pi_WL
443
+
444
+ M2[..., 6] = mZ2
445
+ M2[..., 7] = mZ2L
446
+ M2[..., 8] = mA2
447
+ M2[..., 9] = mA2L
448
+ M2[..., 10] = mW2
449
+ M2[..., 11] = mW2L
450
+
451
+ return M2
452
+
453
+ scalars = [
454
+ Scalar(name="m_h", latex_name=r"$m_h$", dof=1, is_SM=True),
455
+ Scalar(name="m_H", latex_name=r"$m_H$", dof=1, is_SM=False),
456
+ Scalar(name="m_A", latex_name=r"$m_A$", dof=1, is_SM=False),
457
+ Goldstone(name="m_G0", latex_name=r"$m_{G^0}$", dof=1, is_SM=True),
458
+ Scalar(name="m_Hpm", latex_name=r"$m_{H^\pm}$", dof=2, is_SM=False),
459
+ Goldstone(name="m_Gpm", latex_name=r"$m_{G^\pm}$", dof=2, is_SM=True),
460
+ ]
461
+
462
+ sqrt_g = np.sqrt(self.g1**2 + self.g2**2) / 2.0
463
+ gauge_bosons = [
464
+ GaugeBoson(name="m_ZT", latex_name=r"$m_{Z, T}$", dof=2, gauge_coupling=sqrt_g, is_SM=True,),
465
+ GaugeBoson(name="m_ZL", latex_name=r"$m_{Z, L}$", dof=1, gauge_coupling=sqrt_g, is_SM=True,),
466
+ GaugeBoson(name="m_AT", latex_name=r"$m_{A, T}$", dof=2, gauge_coupling=sqrt_g, is_SM=True,),
467
+ GaugeBoson(name="m_AL", latex_name=r"$m_{A, L}$", dof=1, gauge_coupling=sqrt_g, is_SM=True,),
468
+ GaugeBoson(name="m_WT", latex_name=r"$m_{W, T}$", dof=4, gauge_coupling=self.g2 / 2.0, is_SM=True,),
469
+ GaugeBoson(name="m_WL", latex_name=r"$m_{W, L}$", dof=2, gauge_coupling=self.g2 / 2.0, is_SM=True,),
470
+ ]
471
+
472
+ fermions = [
473
+ Fermion(name="m_t", latex_name=r"$m_t$", dof=12, is_SM=True),
474
+ Fermion(name="m_b", latex_name=r"$m_b$", dof=12, is_SM=True),
475
+ Fermion(name="m_tau", latex_name=r"$m_{\\tau}$", dof=4, is_SM=True),
476
+ ]
477
+
478
+ def fermion_mass_function(X):
479
+ X = np.asarray(X, dtype=float)
480
+ phi1 = X[..., 0]
481
+ phi2 = X[..., 1]
482
+
483
+ Nfermions = 3
484
+ M2 = np.empty(phi1.shape + (Nfermions,))
485
+
486
+ mt_sq = (self.yt * phi2) ** 2
487
+ bottom_field = phi2 if self._bottom_uses_phi2 else phi1
488
+ lepton_field = phi2 if self._lepton_uses_phi2 else phi1
489
+ mb_sq = (self.yb * bottom_field) ** 2
490
+ mtau_sq = (self.ytau * lepton_field) ** 2
491
+
492
+ M2[..., 0] = mt_sq
493
+ M2[..., 1] = mb_sq
494
+ M2[..., 2] = mtau_sq
495
+
496
+ return M2
497
+
498
+
499
+ spectrum = MassSpectrum(scalars=scalars, gaugeBosons=gauge_bosons,
500
+ boson_massSq_fn=boson_mass_function,
501
+ fermions=fermions, fermion_massSq_fn=fermion_mass_function)
502
+
503
+ return spectrum
504
+
505
+ # ------------------------------------------------------------------
506
+ # Miscellaneous
507
+ # ------------------------------------------------------------------
508
+ def forbidPhaseCrit(self, X):
509
+ return False
510
+
511
+ def approxZeroTMin(self):
512
+ return [np.array([self.v1, self.v2])]