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.
- transitionlistener/__init__.py +21 -0
- transitionlistener/bubbledynamics.py +2250 -0
- transitionlistener/bubbledynamics_fixedstep.py +2929 -0
- transitionlistener/check_installation.py +309 -0
- transitionlistener/ckm.py +91 -0
- transitionlistener/colors.py +288 -0
- transitionlistener/config.py +185 -0
- transitionlistener/constants.py +64 -0
- transitionlistener/counterterms/__init__.py +230 -0
- transitionlistener/counterterms/cw.py +298 -0
- transitionlistener/counterterms/tensors.py +343 -0
- transitionlistener/counterterms/twohdm.py +520 -0
- transitionlistener/counterterms/twohdm_solver.py +374 -0
- transitionlistener/errors.py +315 -0
- transitionlistener/examples/bp_et.yaml +64 -0
- transitionlistener/examples/bp_lisa.yaml +70 -0
- transitionlistener/examples/bp_muares.yaml +69 -0
- transitionlistener/examples/bp_pta.yaml +64 -0
- transitionlistener/examples/example_dark_photon.yaml +73 -0
- transitionlistener/examples/example_grid.yaml +55 -0
- transitionlistener/examples/example_line.yaml +51 -0
- transitionlistener/examples/example_point.yaml +73 -0
- transitionlistener/examples/example_random_conformal.yaml +42 -0
- transitionlistener/examples/example_ultranest.yaml +39 -0
- transitionlistener/finiteT.py +468 -0
- transitionlistener/generic_potential.py +1521 -0
- transitionlistener/gridplots.py +592 -0
- transitionlistener/gwfopt.py +604 -0
- transitionlistener/helper_functions.py +843 -0
- transitionlistener/hydrodynamics.py +647 -0
- transitionlistener/interface/__init__.py +95 -0
- transitionlistener/interface/check.py +51 -0
- transitionlistener/interface/cli.py +211 -0
- transitionlistener/interface/config_loader.py +264 -0
- transitionlistener/interface/logging_utils.py +30 -0
- transitionlistener/interface/output_schema.py +296 -0
- transitionlistener/interface/pipeline.py +300 -0
- transitionlistener/interface/samplers.py +565 -0
- transitionlistener/interface/scans.py +468 -0
- transitionlistener/interface/single_point.py +581 -0
- transitionlistener/interface/state.py +61 -0
- transitionlistener/lineplots.py +597 -0
- transitionlistener/logo/TL-logo_large.png +0 -0
- transitionlistener/logo/TL-logo_small.png +0 -0
- transitionlistener/models/TL_2HDM.py +512 -0
- transitionlistener/models/TL_conformal_dark_u1.py +202 -0
- transitionlistener/models/TL_dark_U1.py +198 -0
- transitionlistener/models/TL_dark_U1_g_parameterization.py +198 -0
- transitionlistener/models/TL_dark_flipflop.py +274 -0
- transitionlistener/models/templatePotential.py +260 -0
- transitionlistener/nucleation.py +412 -0
- transitionlistener/observability.py +790 -0
- transitionlistener/particles.py +436 -0
- transitionlistener/pathDeformation.py +1462 -0
- transitionlistener/percolation_adaptive_gridbuilders.py +1385 -0
- transitionlistener/percolation_adaptive_rate.py +1049 -0
- transitionlistener/percolation_adaptivestepsize.py +1632 -0
- transitionlistener/percolation_fixedstepsize.py +618 -0
- transitionlistener/phases.py +1499 -0
- transitionlistener/plot_settings.py +121 -0
- transitionlistener/plots.py +1781 -0
- transitionlistener/runtime_options.py +278 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/bandwidths.npy +0 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/density.npy +0 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/freqs.npy +0 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log.txt +16 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log10rhogrid.npy +0 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/log10rholabels.txt +30 -0
- transitionlistener/tab_data/30f_fs{hd}_100fDMGP_ceffyl/pulsar_list.txt +1 -0
- transitionlistener/tab_data/HLV-O2-PLI.csv +82 -0
- transitionlistener/tab_data/HLV-O2-noise.csv +83 -0
- transitionlistener/tab_data/HLVK-design-PLI.csv +61 -0
- transitionlistener/tab_data/HLVK-design-noise.csv +83 -0
- transitionlistener/tab_data/NG15_PLI_hc.csv +31 -0
- transitionlistener/tab_data/NG15_noise_hc.csv +56 -0
- transitionlistener/tab_data/PLI-dataset.csv +327 -0
- transitionlistener/tab_data/energydensities.dat +1001 -0
- transitionlistener/tab_data/finiteT_b.dat.txt +1999 -0
- transitionlistener/tab_data/finiteT_f.dat.txt +1000 -0
- transitionlistener/tab_data/geff_SM.dat +10009 -0
- transitionlistener/tab_data/muAres_f_Hz_PLI_h2OmegaGW.csv +131 -0
- transitionlistener/tab_data/muAres_f_Hz_h2Omega_noise.csv +99 -0
- transitionlistener/tab_data/noise-dataset.csv +327 -0
- transitionlistener/tab_data/numberdensities.dat +1001 -0
- transitionlistener/tab_data/pressures.dat +1001 -0
- transitionlistener/thermodynamics.py +686 -0
- transitionlistener/transitionObservables.py +1199 -0
- transitionlistener/transitionObservables_fixedstep.py +976 -0
- transitionlistener/transitions.py +1000 -0
- transitionlistener/tunneling1D.py +910 -0
- transitionlistener-2.0.0.dist-info/METADATA +817 -0
- transitionlistener-2.0.0.dist-info/RECORD +95 -0
- transitionlistener-2.0.0.dist-info/WHEEL +4 -0
- transitionlistener-2.0.0.dist-info/entry_points.txt +2 -0
- transitionlistener-2.0.0.dist-info/licenses/LICENSE.txt +674 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the Higgs potential for a dark sector model with two singlet scalars
|
|
3
|
+
which can mix with each other, but not with the SM Higgs. The purpose of this model is to
|
|
4
|
+
study possible phase transition in a two-dimensional field space.
|
|
5
|
+
|
|
6
|
+
Part of TransitionListener v2.0
|
|
7
|
+
Documentation: https://tasillo.de/TransitionListener/
|
|
8
|
+
|
|
9
|
+
Authors:
|
|
10
|
+
Jonas Matuszak <jonas.matuszak@kit.edu>
|
|
11
|
+
Carlo Tasillo <carlo.tasillo@ific.uv.es>
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
from scipy import optimize
|
|
16
|
+
from transitionlistener import generic_potential
|
|
17
|
+
from transitionlistener import config
|
|
18
|
+
from transitionlistener import helper_functions
|
|
19
|
+
from transitionlistener import constants as cn
|
|
20
|
+
from transitionlistener.particles import MassSpectrum, Scalar, Fermion
|
|
21
|
+
from transitionlistener.errors import InitPotentialError
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DarkFlipFlop(generic_potential.generic_potential):
|
|
26
|
+
"""Dark flip-flop model with two interacting singlets."""
|
|
27
|
+
|
|
28
|
+
model_parameters = {
|
|
29
|
+
"lambda0": {
|
|
30
|
+
"default": 0.1,
|
|
31
|
+
"plotname": r"$\lambda_0$",
|
|
32
|
+
"min": 0,
|
|
33
|
+
"max": np.inf},
|
|
34
|
+
"gamma": {
|
|
35
|
+
"default": 1,
|
|
36
|
+
"plotname": r"$\gamma$",
|
|
37
|
+
"min": 0,
|
|
38
|
+
"max": np.inf},
|
|
39
|
+
"lambda1": {
|
|
40
|
+
"default": 0.1,
|
|
41
|
+
"plotname": r"$\lambda_1$",
|
|
42
|
+
"min": 0,
|
|
43
|
+
"max": np.inf},
|
|
44
|
+
"lambda12": {
|
|
45
|
+
"default": 0.1,
|
|
46
|
+
"plotname": r"$\lambda_{12}$",
|
|
47
|
+
"min": 0,
|
|
48
|
+
"max": np.inf},
|
|
49
|
+
"v_GeV": {
|
|
50
|
+
"default": 0.1,
|
|
51
|
+
"plotname": r"$v$ [GeV]",
|
|
52
|
+
"min": 0,
|
|
53
|
+
"max": np.inf},
|
|
54
|
+
"y": {
|
|
55
|
+
"default": 1,
|
|
56
|
+
"plotname": r"$y$",
|
|
57
|
+
"min": 0,
|
|
58
|
+
"max": np.inf},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
def init(self, inputparam_dict, verbose=True):
|
|
62
|
+
"""Initialise the flip-flop scalar potential with user-supplied parameters."""
|
|
63
|
+
self.mp = self.set_modelparams(inputparam_dict)
|
|
64
|
+
lambda0, gamma, lambda1, lambda12, v_GeV, y = [self.mp[name]["value"] for name in self.mp.keys()]
|
|
65
|
+
self.retrieved_input = np.array([lambda0, gamma, lambda1, lambda12, v_GeV, y])
|
|
66
|
+
self.Ndim = 2
|
|
67
|
+
|
|
68
|
+
self.lambda0 = lambda0
|
|
69
|
+
self.gamma = gamma
|
|
70
|
+
self.lambda1 = lambda1
|
|
71
|
+
self.lambda12 = lambda12
|
|
72
|
+
self.v_GeV = v_GeV
|
|
73
|
+
self.y = y
|
|
74
|
+
self.verbose = verbose
|
|
75
|
+
|
|
76
|
+
self.v_stable = 1000
|
|
77
|
+
self.v = self.v_stable
|
|
78
|
+
self.daisy = "ArnoldEspinosa"
|
|
79
|
+
self.Z2_cutoff = -5
|
|
80
|
+
self.conversionFactor = self.computeConversionFactor(self.v_stable, v_GeV)
|
|
81
|
+
self.xi_nuc = 1
|
|
82
|
+
|
|
83
|
+
self.v2_GeV2 = v_GeV**2
|
|
84
|
+
|
|
85
|
+
self.v2 = self.v2_GeV2 / self.conversionFactor**2
|
|
86
|
+
self.renormScaleSq = self.v2
|
|
87
|
+
|
|
88
|
+
self.mass_spectrum = self._build_mass_spectrum()
|
|
89
|
+
|
|
90
|
+
self.dmu1 = 0.0
|
|
91
|
+
self.dmu2 = 0.0
|
|
92
|
+
self.dlambda1 = 0.0
|
|
93
|
+
self.dlambda2 = 0.0
|
|
94
|
+
self.dlambda12 = 0.0
|
|
95
|
+
self.calcCounterTerms()
|
|
96
|
+
|
|
97
|
+
# The next line sets the field values of the absolute minimum.
|
|
98
|
+
def fmin(x, t):
|
|
99
|
+
return optimize.fmin(self.Vtot, x, args=(t,), xtol=self.x_eps, disp=False)
|
|
100
|
+
|
|
101
|
+
# X0_1 = fmin([0, self.v], self.Tmin)
|
|
102
|
+
# X0_2 = fmin([self.v, 0], self.Tmin)
|
|
103
|
+
# Its better to use the analytical minima as a starting point here
|
|
104
|
+
self.Tmin = cn.T0_SM_GeV / self.conversionFactor
|
|
105
|
+
X0_1 = fmin([0, self.v/gamma], self.Tmin)
|
|
106
|
+
X0_2 = fmin([self.v*np.sqrt(1 + lambda1/lambda0), 0], self.Tmin)
|
|
107
|
+
V0_1 = self.Vtot(X0_1, self.Tmin)
|
|
108
|
+
V0_2 = self.Vtot(X0_2, self.Tmin)
|
|
109
|
+
self.X0 = X0_1 if V0_1 < V0_2 else X0_2
|
|
110
|
+
|
|
111
|
+
bosons_Tmin = self.boson_massSq(self.X0, self.Tmin)
|
|
112
|
+
self.m1sq_Tmin = float(bosons_Tmin[0][..., 0])
|
|
113
|
+
self.m2sq_Tmin = float(bosons_Tmin[0][..., 1])
|
|
114
|
+
self.m1_Tmin_GeV = np.sqrt(self.m1sq_Tmin) * self.conversionFactor
|
|
115
|
+
self.m2_Tmin_GeV = np.sqrt(self.m2sq_Tmin) * self.conversionFactor
|
|
116
|
+
self.derived_param_names = [name for name in config.all_observables.keys()]
|
|
117
|
+
self.derived_param_plot_names = [config.all_observables[name] for name in self.derived_param_names]
|
|
118
|
+
|
|
119
|
+
# if self.m1_Tmin_GeV < 0.2 or self.m2_Tmin_GeV < 0.2:
|
|
120
|
+
# # This is an ad-hoc cut to avoid very light scalars that are ruled out by
|
|
121
|
+
# # BBN DNeff constraints. Above 200 MeV they can decay to muons and are
|
|
122
|
+
# # hence safe.
|
|
123
|
+
# msg = ("The scalar masses are below 200 MeV "
|
|
124
|
+
# "at T=0: m1 = {:.3f} GeV, m2 = {:.3f} GeV.".format(
|
|
125
|
+
# self.m1_Tmin_GeV, self.m2_Tmin_GeV))
|
|
126
|
+
# raise InitPotentialError(msg)
|
|
127
|
+
|
|
128
|
+
if self.verbose:
|
|
129
|
+
input_dict = {
|
|
130
|
+
"lambda0": self.lambda0,
|
|
131
|
+
"gamma": self.gamma,
|
|
132
|
+
"lambda1": self.lambda1,
|
|
133
|
+
"lambda12": self.lambda12,
|
|
134
|
+
"v / GeV": self.v_GeV
|
|
135
|
+
}
|
|
136
|
+
derived_dict = {
|
|
137
|
+
"v / i.u.": self.v,
|
|
138
|
+
"m1 / GeV": self.m1_Tmin_GeV,
|
|
139
|
+
"m2 / GeV": self.m2_Tmin_GeV,
|
|
140
|
+
}
|
|
141
|
+
self.makePrettyDictionaryPrint(derived_dict)
|
|
142
|
+
|
|
143
|
+
def setConfigParameters(self) -> None:
|
|
144
|
+
"""Change the default config parameters for tracing, hydrodynamics, and GW
|
|
145
|
+
computation.
|
|
146
|
+
"""
|
|
147
|
+
self.config.tracingConf.gen_mirror_phases = False
|
|
148
|
+
self.config.tracingConf.tracing_field_accuracy = 1e-3
|
|
149
|
+
# self.config.gwConf.weak_threshold = 5e-2 # This could be a bit low if alpha_nuc << alpha_perc
|
|
150
|
+
self.config.gwConf.weak_threshold = 1e-4
|
|
151
|
+
# self.config.tracingConf.internal_scale = 1000
|
|
152
|
+
# self.config.tracingConf.Tmax_factor = 2.5
|
|
153
|
+
# ...
|
|
154
|
+
|
|
155
|
+
def calcCounterTerms(self, eps=0.1) -> None:
|
|
156
|
+
"""Compute the counter terms of the MS bar scheme."""
|
|
157
|
+
v1 = self.v * np.sqrt(1 + self.lambda1/self.lambda0)
|
|
158
|
+
|
|
159
|
+
def V_coleman_weinberg(X):
|
|
160
|
+
bosons = self.boson_massSq(X, 0.0)
|
|
161
|
+
fermions = self.fermion_massSq(X)
|
|
162
|
+
return self.V1(bosons, fermions)
|
|
163
|
+
|
|
164
|
+
# Take the derivative with larger \Delta\phi, this improves stability!
|
|
165
|
+
dV1 = helper_functions.gradientFunction(
|
|
166
|
+
# V_coleman_weinberg, eps=self.x_eps, Ndim=self.Ndim, order=self.deriv_order)
|
|
167
|
+
V_coleman_weinberg, eps=eps, Ndim=self.Ndim, order=self.deriv_order)
|
|
168
|
+
|
|
169
|
+
d2V1 = helper_functions.hessianFunction(
|
|
170
|
+
# V_coleman_weinberg, eps=self.x_eps, Ndim=self.Ndim, order=self.deriv_order)
|
|
171
|
+
V_coleman_weinberg, eps=eps, Ndim=self.Ndim, order=self.deriv_order)
|
|
172
|
+
|
|
173
|
+
dVdx1 = dV1([v1, 0])[0]
|
|
174
|
+
d2Vdx1 = d2V1([v1, 0])[0, 0]
|
|
175
|
+
d2Vdx2 = d2V1([v1, 0])[1, 1]
|
|
176
|
+
# d2Vdx2 = d2V1([0, v2])[1,1]
|
|
177
|
+
|
|
178
|
+
self.dmu1 = 3/(2*v1) * dVdx1 - 0.5 * d2Vdx1
|
|
179
|
+
self.dmu2 = d2Vdx2
|
|
180
|
+
self.dlambda1 = 0.5/v1**3 * dVdx1 - 0.5/v1**2 * d2Vdx1
|
|
181
|
+
self.dlambda2 = 0.0
|
|
182
|
+
self.dlambda12 = 0.0
|
|
183
|
+
|
|
184
|
+
def forbidPhaseCrit(self, X):
|
|
185
|
+
"""Return True when a candidate minimum should be excluded by symmetry."""
|
|
186
|
+
Z2_1 = (np.array([X])[..., 0] < self.Z2_cutoff).any()
|
|
187
|
+
Z2_2 = (np.array([X])[..., 1] < self.Z2_cutoff).any()
|
|
188
|
+
return Z2_1 or Z2_2
|
|
189
|
+
|
|
190
|
+
def V0(self, X):
|
|
191
|
+
"""Evaluate the tree-level potential for the scalar doublet."""
|
|
192
|
+
X = np.asanyarray(X)
|
|
193
|
+
phi1 = X[..., 0]
|
|
194
|
+
phi2 = X[..., 1]
|
|
195
|
+
r = .25*self.lambda0*(phi1**2 + self.gamma**2 * phi2**2 - self.v2)**2
|
|
196
|
+
r += -.5 * self.lambda1 * self.v2 * phi1**2
|
|
197
|
+
r += .5 * self.lambda12 * phi1**2 * phi2**2
|
|
198
|
+
return r
|
|
199
|
+
|
|
200
|
+
def Vct(self, X):
|
|
201
|
+
r"""The counter terms in the MS bar scheme.
|
|
202
|
+
|
|
203
|
+
.. math::
|
|
204
|
+
`V_{ct} = - \frac{\delta\mu_1^2}{2} \phi_1^{2} - \frac{\delta\mu_2^2}{2} \phi_{2}^{2} +
|
|
205
|
+
\frac{\delta\lambda_{1}}{4}\phi_{1}^{4} +
|
|
206
|
+
\frac{\delta\lambda_{2}}{4}\phi_{2}^4 + \frac{\delta\lambda_{12}}{2}\phi_{1}^2\phi_2^2`
|
|
207
|
+
"""
|
|
208
|
+
X = np.asarray(X)
|
|
209
|
+
phi1 = X[..., 0]
|
|
210
|
+
phi2 = X[..., 1]
|
|
211
|
+
|
|
212
|
+
Vct = - 0.5*self.dmu1*phi1**2 - 0.5*self.dmu2*phi2**2
|
|
213
|
+
Vct += 0.25*self.dlambda1*phi1**4 + 0.25*self.dlambda2*phi2**2
|
|
214
|
+
Vct += 0.5*self.dlambda12 * phi1**2 * phi2**2
|
|
215
|
+
return Vct
|
|
216
|
+
|
|
217
|
+
def _build_mass_spectrum(self) -> MassSpectrum:
|
|
218
|
+
|
|
219
|
+
scalar1 = Scalar(name="m_h1", latex_name=r"$m_{h_1}$", dof=1, is_SM=False)
|
|
220
|
+
scalar2 = Scalar(name="m_h2", latex_name=r"$m_{h_2}$", dof=1, is_SM=False)
|
|
221
|
+
|
|
222
|
+
def boson_mass_function(X, T):
|
|
223
|
+
X = np.asarray(X)
|
|
224
|
+
phi1 = X[..., 0]
|
|
225
|
+
phi2 = X[..., 1]
|
|
226
|
+
T_arr = np.asarray(T, dtype=float)
|
|
227
|
+
T2 = T_arr * T_arr
|
|
228
|
+
if T2.ndim == 0:
|
|
229
|
+
T2 = T2 + np.zeros_like(phi1)
|
|
230
|
+
|
|
231
|
+
a = 2 * self.lambda0 * phi1**2
|
|
232
|
+
a += self.lambda0 * (phi1**2 + self.gamma**2 * phi2**2 - self.v2)
|
|
233
|
+
a += -self.lambda1 * self.v2 + self.lambda12 * phi2**2
|
|
234
|
+
|
|
235
|
+
b = 2 * self.gamma**4 * self.lambda0 * phi2**2
|
|
236
|
+
b += self.lambda0 * self.gamma**2 * (phi1**2 + self.gamma**2 * phi2**2 - self.v2)
|
|
237
|
+
b += self.lambda12 * phi1**2
|
|
238
|
+
|
|
239
|
+
coeff1 = (self.y**2 + 2 * ((3 + self.gamma**2) * self.lambda0 + self.lambda12)) / 24.0
|
|
240
|
+
coeff2 = (self.gamma**2 * self.lambda0 + 3 * self.gamma**4 * self.lambda0 + self.lambda12) / 12.0
|
|
241
|
+
a += coeff1 * T2
|
|
242
|
+
b += coeff2 * T2
|
|
243
|
+
|
|
244
|
+
c = 2 * self.gamma**2 * self.lambda0 * phi1 * phi2 + 2 * self.lambda12 * phi1 * phi2
|
|
245
|
+
|
|
246
|
+
A = 0.5 * (a + b)
|
|
247
|
+
B = np.sqrt(0.25 * (a - b) ** 2 + c ** 2)
|
|
248
|
+
m1sq = A + B
|
|
249
|
+
m2sq = A - B
|
|
250
|
+
|
|
251
|
+
return np.stack((m1sq, m2sq), axis=-1)
|
|
252
|
+
|
|
253
|
+
fermion = Fermion(name="m_psi", latex_name=r"$m_{\psi}$", dof=2, is_SM=False)
|
|
254
|
+
|
|
255
|
+
def fermion_mass_function(X):
|
|
256
|
+
X = np.asarray(X)
|
|
257
|
+
phi1 = X[..., 0]
|
|
258
|
+
m2psi = 0.5 * self.y**2 * phi1**2
|
|
259
|
+
return np.stack((m2psi,), axis=-1)
|
|
260
|
+
|
|
261
|
+
spectrum = MassSpectrum([scalar1, scalar2], fermions=[fermion],
|
|
262
|
+
boson_massSq_fn=boson_mass_function,
|
|
263
|
+
fermion_massSq_fn=fermion_mass_function)
|
|
264
|
+
|
|
265
|
+
return spectrum
|
|
266
|
+
|
|
267
|
+
def approxZeroTMin(self):
|
|
268
|
+
"""Return approximate zero-temperature minima for the flip-flop model."""
|
|
269
|
+
# There are generically two minima at zero temperature in this model,
|
|
270
|
+
# and we want to include both of them.
|
|
271
|
+
v = self.v2**.5
|
|
272
|
+
v1 = v/self.gamma
|
|
273
|
+
v2 = v*np.sqrt(1 + self.lambda1/self.lambda0)
|
|
274
|
+
return [np.array([0, v1]), np.array([v2, 0])]
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""Template to implement the effective potential of a new model.
|
|
2
|
+
|
|
3
|
+
Part of TransitionListener v2.0
|
|
4
|
+
Documentation: https://tasillo.de/TransitionListener/
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Jonas Matuszak <jonas.matuszak@kit.edu>
|
|
8
|
+
Carlo Tasillo <carlo.tasillo@ific.uv.es>
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from transitionlistener.generic_potential import generic_potential
|
|
13
|
+
import transitionlistener.constants as c
|
|
14
|
+
from transitionlistener import config
|
|
15
|
+
from transitionlistener.particles import MassSpectrum, Scalar, Goldstone, GaugeBoson, Fermion
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Rename the class to match your implemented model
|
|
20
|
+
class TemplatePotenital(generic_potential):
|
|
21
|
+
"""Template potential"""
|
|
22
|
+
|
|
23
|
+
# Specify the
|
|
24
|
+
model_parameters = {
|
|
25
|
+
"m1_GeV": {
|
|
26
|
+
"default": 125.20,
|
|
27
|
+
"plotname": r"$m_1$ [GeV]",
|
|
28
|
+
"min": 0,
|
|
29
|
+
"max": np.inf},
|
|
30
|
+
"g": {
|
|
31
|
+
"default": 0.5,
|
|
32
|
+
"plotname": r"$g$",
|
|
33
|
+
"min": 0,
|
|
34
|
+
"max": 4*np.pi
|
|
35
|
+
},
|
|
36
|
+
"l": {
|
|
37
|
+
"default": 1e-3,
|
|
38
|
+
"plotname": r"$\lambda$",
|
|
39
|
+
"min": 0,
|
|
40
|
+
"max": 4*np.pi
|
|
41
|
+
},
|
|
42
|
+
"y": {
|
|
43
|
+
"default": 0.1,
|
|
44
|
+
"plotname": r"$y$",
|
|
45
|
+
"min": 0,
|
|
46
|
+
"max": np.sqrt(2)*4*np.pi,
|
|
47
|
+
},
|
|
48
|
+
"v_GeV": {
|
|
49
|
+
"default": 246.22,
|
|
50
|
+
"plotname": r"$v$ [GeV]",
|
|
51
|
+
"min": 0,
|
|
52
|
+
"max": np.inf},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
def init(self, input_dict, verbose=True):
|
|
56
|
+
"""Perform the initialisation of the potential"""
|
|
57
|
+
self.verbose = verbose
|
|
58
|
+
|
|
59
|
+
# Specify the number of scalar field dimension:
|
|
60
|
+
self.Ndim = 1
|
|
61
|
+
|
|
62
|
+
# read input and set (default) values
|
|
63
|
+
self.mp = self.set_modelparams(input_dict)
|
|
64
|
+
self.m1_GeV = self.mp["m1_GeV"]["value"]
|
|
65
|
+
self.v_GeV = self.mp["v_GeV"]["value"]
|
|
66
|
+
self.y = self.mp["y"]["value"]
|
|
67
|
+
self.l = self.mp["l"]["value"]
|
|
68
|
+
self.g = self.mp["g"]["value"]
|
|
69
|
+
|
|
70
|
+
# Use the vev in internal units, normalised to 1000 by default
|
|
71
|
+
self.v = self.v_stable
|
|
72
|
+
self.conversionFactor = self.computeConversionFactor(self.v_stable, self.v_GeV)
|
|
73
|
+
self.daisy = "ArnoldEspinosa" # or: "Parwani" or "off"
|
|
74
|
+
|
|
75
|
+
# Set any parameters derived from the input
|
|
76
|
+
self.mu2 = -2 * self.v**2
|
|
77
|
+
self.mu2_GeV = - 2 * self.v_GeV**2
|
|
78
|
+
|
|
79
|
+
# Set the T = 0 minima, this has to have the shape (1, Ndim)
|
|
80
|
+
self.X0 = np.array([self.v])
|
|
81
|
+
|
|
82
|
+
# Build particle spectrum definition used throughout the potential
|
|
83
|
+
self.mass_spectrum = self.build_mass_spectrum()
|
|
84
|
+
|
|
85
|
+
# Set the renormalization scale
|
|
86
|
+
self.renormScaleSq = self.v**2 # In internal units
|
|
87
|
+
self.renormScaleSq_GeV2 = self.renormScaleSq * self.conversionFactor**2. # In GeV
|
|
88
|
+
self.renormScale_GeV = np.sqrt(self.renormScaleSq) * self.conversionFactor
|
|
89
|
+
|
|
90
|
+
# Impose the renormalization conditions on the potential.
|
|
91
|
+
dV1 = self.dV1atvev()
|
|
92
|
+
d2V1 = self.d2V1atvev()
|
|
93
|
+
self.dmu2 = 3./2. * dV1 / self.v - 1./2. * d2V1
|
|
94
|
+
self.dmu2_GeV2 = self.dmu2 * self.conversionFactor**2.
|
|
95
|
+
self.dl = 1./2. * dV1 / self.v**3. - 1./2. * d2V1 / self.v**2.
|
|
96
|
+
|
|
97
|
+
# Get the zero temperature masses in the global vev
|
|
98
|
+
bosonMassSq_vev, _, _, _ = self.boson_massSq(self.X0, 0.0)
|
|
99
|
+
|
|
100
|
+
# Set the background degrees of freedom:
|
|
101
|
+
# The defaults includes the SM degrees of freedom, i.e. the sector undergoing the
|
|
102
|
+
# phase transition is coupled to the SM during the phase transition.
|
|
103
|
+
# self.kin_coupled_e_geff = e_geffSM # This can be overwritten
|
|
104
|
+
# self.kin_coupled_p_geff = p_geffSM # This can be overwritten
|
|
105
|
+
|
|
106
|
+
# This specifies additional radiation that is not coupled to the sector undergoing
|
|
107
|
+
# a phase transition. If e.g. a dark sector is completely decoupled from the SM,
|
|
108
|
+
# put the SM geff here.
|
|
109
|
+
# self.kin_decoupled_e_geff = lambda T, cf: 0.0 * T # If the SM is decoupled, put e_geffSM here
|
|
110
|
+
# self.kin_decoupled_p_geff = lambda T, cf: 0.0 * T # If the SM is decoupled, put p_geffSM here
|
|
111
|
+
|
|
112
|
+
# Include the input and derived parameters in the class.
|
|
113
|
+
self.derived_param_names = [name for name in config.all_observables.keys()]
|
|
114
|
+
self.derived_param_plot_names = [config.all_observables[name] for name in self.derived_param_names]
|
|
115
|
+
|
|
116
|
+
if self.verbose:
|
|
117
|
+
input_dict = dict(
|
|
118
|
+
vev_GeV=self.v_GeV,
|
|
119
|
+
vev_iu=self.v,
|
|
120
|
+
quartic_coupling=self.l,
|
|
121
|
+
gauge_coupling=self.g,
|
|
122
|
+
y=self.y,
|
|
123
|
+
conversion_factor_GeV_per_iu=self.conversionFactor
|
|
124
|
+
)
|
|
125
|
+
derived_dict = dict(
|
|
126
|
+
mu2_GeV2=self.mu2_GeV2,
|
|
127
|
+
dmu2_GeV2=self.dmu2_GeV2,
|
|
128
|
+
dl=self.dl,
|
|
129
|
+
renormScale_GeV=self.renormScale_GeV,
|
|
130
|
+
renormScaleSq=self.renormScaleSq)
|
|
131
|
+
self.makePrettyDictionaryPrint(input_dict, derived_dict)
|
|
132
|
+
|
|
133
|
+
def setConfigParameters(self) -> None:
|
|
134
|
+
"""Change the default config parameters for tracing, hydrodynamics, and GW
|
|
135
|
+
computation.
|
|
136
|
+
"""
|
|
137
|
+
self.config.tracingConf.gen_mirror_phases = False
|
|
138
|
+
self.config.tracingConf.tracing_field_accuracy = 1e-3 # for Hessian
|
|
139
|
+
# self.config.tracingConf.internal_scale = 1000
|
|
140
|
+
# self.config.tracingConf.Tmax_factor = 2.5
|
|
141
|
+
# ...
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def forbidPhaseCrit(self, X):
|
|
145
|
+
"""
|
|
146
|
+
forbidPhaseCrit is used since there is a Z2 symmetry in the theory and
|
|
147
|
+
we don't want to double-count all of the phases.
|
|
148
|
+
"""
|
|
149
|
+
return (np.array([X])[..., 0] < self.Z2_cutoff).any()
|
|
150
|
+
|
|
151
|
+
def V0(self, X: np.ndarray) -> np.ndarray:
|
|
152
|
+
""" This method defines the tree-level potential."""
|
|
153
|
+
X = np.asanyarray(X)
|
|
154
|
+
|
|
155
|
+
phi1 = X[..., 0]
|
|
156
|
+
# For Ndims > 1, the other field directions are exctracted as
|
|
157
|
+
# phi2 = X[..., 1]
|
|
158
|
+
# phi3 = X[..., 2]
|
|
159
|
+
|
|
160
|
+
# Compute the contributions to the tree level potential with the
|
|
161
|
+
# model parameters
|
|
162
|
+
V = - self.mu2*(phi1**2.)/2. + self.l*(phi1**4.)/4.
|
|
163
|
+
|
|
164
|
+
# Potentially other field directions contribute, e.g.:
|
|
165
|
+
# V += - self.mu2_2 * phi2**2/2 + self.l_2 * phi2**4/4.
|
|
166
|
+
|
|
167
|
+
return V
|
|
168
|
+
|
|
169
|
+
def Vct(self, X: np.ndarray) -> np.ndarray:
|
|
170
|
+
""" The counterterm lagrangian is the same as the tree level lagrangian but
|
|
171
|
+
with masses and couplings replaced by counter term values (i.e. here
|
|
172
|
+
mu2 -> dmu2 and l -> dl).
|
|
173
|
+
"""
|
|
174
|
+
X = np.array(X)
|
|
175
|
+
phi1 = X[..., 0]
|
|
176
|
+
# For Ndims > 1, the other field directions are exctracted as
|
|
177
|
+
# phi2 = X[..., 1]
|
|
178
|
+
# phi3 = X[..., 2]
|
|
179
|
+
|
|
180
|
+
# Compute the contribution from the counter terms
|
|
181
|
+
V = - self.dmu2*(phi1**2.)/2. + self.dl*(phi1**4.)/4.
|
|
182
|
+
# Potentially other field directions contribute, e.g.:
|
|
183
|
+
# V += - self.dmu2_2 * phi2**2/2 + self.dl_2 * phi2**4/4.
|
|
184
|
+
|
|
185
|
+
return V
|
|
186
|
+
|
|
187
|
+
def build_mass_spectrum(self) -> MassSpectrum:
|
|
188
|
+
"""This function constructs the mass spectrum by specifying
|
|
189
|
+
the particle content and the mass functions."""
|
|
190
|
+
|
|
191
|
+
# First the scalar particles have to be specified.
|
|
192
|
+
scalar_particles = [
|
|
193
|
+
Scalar(name="m_phi", latex_name=r"$m_\phi$", dof=1, is_SM=False),
|
|
194
|
+
Goldstone(name="m_varphi", latex_name=r"$m_\varphi$", dof=1, is_SM=False),
|
|
195
|
+
]
|
|
196
|
+
|
|
197
|
+
# For the gauge bosons, split the longitudinal and transversal
|
|
198
|
+
# components due to the different thermal masses
|
|
199
|
+
gauge_particles = [
|
|
200
|
+
GaugeBoson(name="m_ZT", latex_name=r"$m_{Z^\prime, T}$", dof=2, gauge_coupling=self.g, is_SM=False),
|
|
201
|
+
GaugeBoson(name="m_ZL", latex_name=r"$m_{Z^\prime, L}$", dof=1, gauge_coupling=self.g, is_SM=False),
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
def boson_mass_function(X, T):
|
|
205
|
+
"""This returns the squared masses of the bosonic particles."""
|
|
206
|
+
X = np.asarray(X)
|
|
207
|
+
T = np.asarray(T)
|
|
208
|
+
|
|
209
|
+
phi = X[..., 0]
|
|
210
|
+
phi_sq = phi*phi
|
|
211
|
+
|
|
212
|
+
Pi_phi = (self.l/3.0 + self.g**2 / 4.0 + self.y**2/12) * T*T # Hard thermal masses scalar
|
|
213
|
+
Pi_Z = (self.g**2/3.0) * T*T # Hard thermal masses gauge boson
|
|
214
|
+
|
|
215
|
+
mPhi_sq = - self.mu2 + 3.0 * self.l * phi_sq
|
|
216
|
+
mVarphi_sq = -self.mu2 + self.l * phi_sq
|
|
217
|
+
mZT_sq = self.g**2 * phi_sq
|
|
218
|
+
mZL_sq = self.g**2 * phi_sq
|
|
219
|
+
|
|
220
|
+
# Four entries
|
|
221
|
+
Nbosons = 4
|
|
222
|
+
M2 = np.empty(phi.shape + (Nbosons,))
|
|
223
|
+
# This has to have the same order as the
|
|
224
|
+
# scalar_particles
|
|
225
|
+
M2[..., 0] = mPhi_sq + Pi_phi
|
|
226
|
+
M2[..., 1] = mVarphi_sq + Pi_phi
|
|
227
|
+
# and the same order as the gauge_particles
|
|
228
|
+
M2[..., 2] = mZT_sq
|
|
229
|
+
M2[..., 3] = mZL_sq + Pi_Z
|
|
230
|
+
|
|
231
|
+
# Add additional bosonic particles:
|
|
232
|
+
# M2[..., 4] = ...
|
|
233
|
+
# M2[..., 5] = ...
|
|
234
|
+
|
|
235
|
+
return M2
|
|
236
|
+
|
|
237
|
+
# specify the fermionic particles:
|
|
238
|
+
fermion_particles = [
|
|
239
|
+
Fermion(name="m_chi", latex_name=r"$m_chi$", dof=4, is_SM=False),
|
|
240
|
+
]
|
|
241
|
+
|
|
242
|
+
def fermion_mass_function(X):
|
|
243
|
+
"""Compute the squared masses of the fermionic particles."""
|
|
244
|
+
X = np.asarray(X)
|
|
245
|
+
phi = X[..., 0]
|
|
246
|
+
mChi = self.y**2/2.0 * phi**2
|
|
247
|
+
return np.stack((mChi,), axis=-1)
|
|
248
|
+
|
|
249
|
+
# Construct the complete mass spectrum contributing to the potential
|
|
250
|
+
spectrum = MassSpectrum(scalars=scalar_particles,
|
|
251
|
+
gaugeBosons=gauge_particles,
|
|
252
|
+
fermions=fermion_particles,
|
|
253
|
+
boson_massSq_fn=boson_mass_function,
|
|
254
|
+
fermion_massSq_fn=fermion_mass_function)
|
|
255
|
+
|
|
256
|
+
return spectrum
|
|
257
|
+
|
|
258
|
+
def approxZeroTMin(self):
|
|
259
|
+
"""Return approximate zero-temperature minima."""
|
|
260
|
+
return self.X0
|