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,976 @@
|
|
|
1
|
+
"""Compute thermodynamic and gravitational-wave observables for transitions.
|
|
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 dataclasses import dataclass
|
|
13
|
+
from scipy import interpolate
|
|
14
|
+
from transitionlistener.generic_potential import generic_potential
|
|
15
|
+
from transitionlistener.phases import PhaseInfo
|
|
16
|
+
from transitionlistener import config
|
|
17
|
+
from transitionlistener.transitions import TransitionInfo
|
|
18
|
+
from . import thermodynamics as td
|
|
19
|
+
from . import errors
|
|
20
|
+
from transitionlistener.hydrodynamics import Hydrodynamics, calc_kappas
|
|
21
|
+
from transitionlistener.bubbledynamics_fixedstep import (
|
|
22
|
+
calcPercAndEvolve,
|
|
23
|
+
calcAlphas,
|
|
24
|
+
calc_betaH_S3,
|
|
25
|
+
calc_betaH_S3_approx,
|
|
26
|
+
calcMeanBubbleSeparation,
|
|
27
|
+
calcMeanBubbleSeparationwExp,
|
|
28
|
+
calcTf,
|
|
29
|
+
HubbleParameter,
|
|
30
|
+
energyDensity,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from . import console, print
|
|
34
|
+
import rich
|
|
35
|
+
from rich.panel import Panel
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class TransitionObservableInfo:
|
|
40
|
+
"""Collection of transition observable data."""
|
|
41
|
+
v_wall: float = np.nan
|
|
42
|
+
c_s: float = np.nan
|
|
43
|
+
c_s_sym: float = np.nan
|
|
44
|
+
c_s_bro: float = np.nan
|
|
45
|
+
Tperc: float = np.nan
|
|
46
|
+
Tperc_SM_GeV: float = np.nan
|
|
47
|
+
Tcrit_SM_GeV: float = np.nan
|
|
48
|
+
xi_crit: float = np.nan
|
|
49
|
+
Tnuc_SM_GeV: float = np.nan
|
|
50
|
+
Treh: float = np.nan
|
|
51
|
+
Treh_SM_GeV: float = np.nan
|
|
52
|
+
alpha: float = np.nan
|
|
53
|
+
alpha_theta: float = np.nan
|
|
54
|
+
alpha_p: float = np.nan
|
|
55
|
+
alpha_e: float = np.nan
|
|
56
|
+
alpha_hyd: float = np.nan
|
|
57
|
+
alpha_inf: float = np.nan
|
|
58
|
+
alpha_eq: float = np.nan
|
|
59
|
+
RH: float = np.nan
|
|
60
|
+
g_eff_tot_reh: float = np.nan
|
|
61
|
+
h_eff_tot_reh: float = np.nan
|
|
62
|
+
g0: float = np.nan
|
|
63
|
+
h0: float = np.nan
|
|
64
|
+
betaH_S3: float = np.nan
|
|
65
|
+
betaH_RH: float = np.nan
|
|
66
|
+
Tf_SM_GeV: float = np.nan
|
|
67
|
+
kappa_phi: float = np.nan
|
|
68
|
+
kappa_sw: float = np.nan
|
|
69
|
+
kappa_turb: float = np.nan
|
|
70
|
+
D: float = np.nan
|
|
71
|
+
step: float = np.nan
|
|
72
|
+
total_steps: float = np.nan
|
|
73
|
+
WARNING_too_weak_to_compute_perc: bool = False
|
|
74
|
+
WARNING_no_perc_splines: bool = False
|
|
75
|
+
WARNING_betaH_small: bool = False
|
|
76
|
+
WARNING_not_T0_global_min: bool = False
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class TransitionContext:
|
|
81
|
+
"""Collect shared inputs and outputs for a single transition."""
|
|
82
|
+
|
|
83
|
+
tr: TransitionInfo
|
|
84
|
+
pot: generic_potential
|
|
85
|
+
phases: list[PhaseInfo]
|
|
86
|
+
GWconfig: config.GWConf
|
|
87
|
+
PercolationConf: config.PercolationConf
|
|
88
|
+
derived_param_names: list[str]
|
|
89
|
+
verbose: bool
|
|
90
|
+
derived_params: dict
|
|
91
|
+
Tnuc: float
|
|
92
|
+
outdict: dict
|
|
93
|
+
phase_symmetric: PhaseInfo
|
|
94
|
+
phase_broken: PhaseInfo
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass
|
|
98
|
+
class PercolationResult:
|
|
99
|
+
"""Hold percolation-related outputs and splines when available."""
|
|
100
|
+
|
|
101
|
+
Tperc: float
|
|
102
|
+
TSYM: np.ndarray | None
|
|
103
|
+
H: np.ndarray | None
|
|
104
|
+
P: np.ndarray | None
|
|
105
|
+
TBRO: np.ndarray | None
|
|
106
|
+
S: np.ndarray | None
|
|
107
|
+
Pint: interpolate.interp1d | None
|
|
108
|
+
Sint: interpolate.interp1d | None
|
|
109
|
+
Hint: interpolate.interp1d | None
|
|
110
|
+
Pexpint: interpolate.interp1d | None
|
|
111
|
+
soundSpSqint: interpolate.interp1d | None
|
|
112
|
+
scalef_r_int: interpolate.interp1d | None
|
|
113
|
+
TBROint: interpolate.interp1d | None
|
|
114
|
+
successful: bool
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class TransitionObservables:
|
|
118
|
+
"""Evaluate derived observables for every transition of a potential."""
|
|
119
|
+
|
|
120
|
+
def __init__(self, pot: generic_potential, phases: list[PhaseInfo],
|
|
121
|
+
transitions: list[TransitionInfo], verbose=False):
|
|
122
|
+
"""Store inputs and immediately compute all derived quantities."""
|
|
123
|
+
self.pot = pot
|
|
124
|
+
self.phases = phases
|
|
125
|
+
self.GWconfig = pot.config.gwConf
|
|
126
|
+
self.PercolationConf = pot.config.percolationConf
|
|
127
|
+
self.transitions = transitions
|
|
128
|
+
self.verbose = verbose
|
|
129
|
+
self.derived_param_names = [name for name in config.all_observables.keys()]
|
|
130
|
+
|
|
131
|
+
if verbose:
|
|
132
|
+
console.print(
|
|
133
|
+
"[green bold]\nStart percolation computation...[/]",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
self.transitionObservables = self.computeTransitionObservables()
|
|
137
|
+
self.check_T0_global_min()
|
|
138
|
+
|
|
139
|
+
def check_T0_global_min(self):
|
|
140
|
+
"""Check whether the global minimum at T = Tmin is the last minimum.
|
|
141
|
+
If not, raise an error.
|
|
142
|
+
"""
|
|
143
|
+
T0 = self.pot.Tmin
|
|
144
|
+
last_vev = self.phases[self.transitions[-1].low_phase].valAt(self.pot.Tmin)
|
|
145
|
+
|
|
146
|
+
if not np.allclose(last_vev, self.pot.X0):
|
|
147
|
+
# The global minimum at T = 0 is not the last minimum!
|
|
148
|
+
|
|
149
|
+
for i, tr in enumerate(self.transitions):
|
|
150
|
+
if tr is not None and tr.type == 1:
|
|
151
|
+
self.transitions[i].derived_params["WARNING:not_T0_global_min"] = True
|
|
152
|
+
self.transitionObservables[i]["WARNING:not_T0_global_min"] = True
|
|
153
|
+
|
|
154
|
+
msg = (
|
|
155
|
+
"The global minimum at T = {} is not the last minimum found "
|
|
156
|
+
"by the phase tracing algorithm. This may be unwanted, for "
|
|
157
|
+
"example if the potential is expected to have a unique "
|
|
158
|
+
"global minimum at T = {} or when identifying the last phase "
|
|
159
|
+
"with the electroweak vacuum."
|
|
160
|
+
).format(T0 * self.pot.conversionFactor, T0 * self.pot.conversionFactor)
|
|
161
|
+
|
|
162
|
+
if self.GWconfig.check_if_T0_global_min:
|
|
163
|
+
console.print(f"[bold red]ERROR:[/bold red] {msg}")
|
|
164
|
+
raise errors.GlobalMinimumError(msg)
|
|
165
|
+
elif self.verbose:
|
|
166
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
167
|
+
console.print(
|
|
168
|
+
"[bold yellow]WARNING:[/bold yellow] "
|
|
169
|
+
"Continuing, because the check_if_T0_global_min flag is "
|
|
170
|
+
"set to False."
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
# The global minimum at T = 0 is the last minimum.
|
|
174
|
+
for i, tr in enumerate(self.transitions):
|
|
175
|
+
if tr is not None and tr.type == 1:
|
|
176
|
+
self.transitions[i].derived_params["WARNING:not_T0_global_min"] = False
|
|
177
|
+
self.transitionObservables[i]["WARNING:not_T0_global_min"] = False
|
|
178
|
+
|
|
179
|
+
if self.verbose:
|
|
180
|
+
msg = (
|
|
181
|
+
"The global minimum at T_min is the last minimum found "
|
|
182
|
+
"by the phase tracing algorithm."
|
|
183
|
+
)
|
|
184
|
+
console.print(
|
|
185
|
+
f"[bold cyan]INFO:[/bold cyan] {msg}"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
def computeTransitionObservables(self):
|
|
189
|
+
"""
|
|
190
|
+
Calculate the GW observables for each transition in the
|
|
191
|
+
transitions_dict. This is done by calling the
|
|
192
|
+
`computeTransitionObservables_one_transition`
|
|
193
|
+
function from the `bubbledynamics` module.
|
|
194
|
+
|
|
195
|
+
Raises
|
|
196
|
+
------
|
|
197
|
+
err
|
|
198
|
+
Raises an error if GW observables cannot be calculated.
|
|
199
|
+
|
|
200
|
+
Returns
|
|
201
|
+
-------
|
|
202
|
+
transitionObservables: dict
|
|
203
|
+
A dictionary with the GW observables for each transition.
|
|
204
|
+
"""
|
|
205
|
+
self.transitionObservables = {i: {} for i in range(len(self.transitions))}
|
|
206
|
+
self.percolationResults = {i: None for i in range(len(self.transitions))}
|
|
207
|
+
self.outdicts = {i: None for i in range(len(self.transitions))}
|
|
208
|
+
|
|
209
|
+
for i, tr in enumerate(self.transitions):
|
|
210
|
+
if tr is not None and tr.type == 1:
|
|
211
|
+
try:
|
|
212
|
+
derived_params_dict_tr, percol, outdict = self.computeTransitionObservables_one_transition(
|
|
213
|
+
tr, nAction=self.PercolationConf.n_action
|
|
214
|
+
)
|
|
215
|
+
self.transitions[i].derived_params = derived_params_dict_tr
|
|
216
|
+
self.percolationResults[i] = percol
|
|
217
|
+
self.outdicts[i] = outdict
|
|
218
|
+
self.transitionObservables[i] = derived_params_dict_tr
|
|
219
|
+
except Exception as err:
|
|
220
|
+
if self.verbose:
|
|
221
|
+
print("Error calculating GW parameters: ", err)
|
|
222
|
+
raise err
|
|
223
|
+
return self.transitionObservables
|
|
224
|
+
|
|
225
|
+
def _initialize_transition_context(self, tr: TransitionInfo) -> TransitionContext:
|
|
226
|
+
"""Prepare reusable data structures for a single transition."""
|
|
227
|
+
derived_params = {
|
|
228
|
+
"WARNING:too_weak_to_compute_perc": False,
|
|
229
|
+
"WARNING:no_perc_splines": False,
|
|
230
|
+
"WARNING:betaH_small": False,
|
|
231
|
+
}
|
|
232
|
+
return TransitionContext(
|
|
233
|
+
tr=tr,
|
|
234
|
+
pot=self.pot,
|
|
235
|
+
phases=self.phases,
|
|
236
|
+
GWconfig=self.GWconfig,
|
|
237
|
+
PercolationConf=self.PercolationConf,
|
|
238
|
+
derived_param_names=self.derived_param_names,
|
|
239
|
+
verbose=self.verbose,
|
|
240
|
+
derived_params=derived_params,
|
|
241
|
+
Tnuc=tr.Tnuc,
|
|
242
|
+
outdict=tr.full_tunneling_info,
|
|
243
|
+
phase_symmetric=self.phases[tr.high_phase],
|
|
244
|
+
phase_broken=self.phases[tr.low_phase],
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
def _ensure_wall_velocity(self, ctx: TransitionContext, T: float) -> None:
|
|
248
|
+
"""Populate v_wall if requested by configuration."""
|
|
249
|
+
if "v_wall" not in ctx.derived_param_names:
|
|
250
|
+
return
|
|
251
|
+
GWconfig = ctx.GWconfig
|
|
252
|
+
derived = ctx.derived_params
|
|
253
|
+
if GWconfig.wall_velocity == "LTE":
|
|
254
|
+
hydr = Hydrodynamics(ctx.pot, ctx.phase_symmetric, ctx.phase_broken, ctx.verbose)
|
|
255
|
+
derived["v_wall"] = hydr.calcWallVelocityLTE(T)
|
|
256
|
+
elif GWconfig.wall_velocity == "c":
|
|
257
|
+
derived["v_wall"] = 1.0
|
|
258
|
+
elif GWconfig.wall_velocity == "WallGo":
|
|
259
|
+
raise NotImplementedError("WallGo is not implemented yet.")
|
|
260
|
+
else:
|
|
261
|
+
vw = 0.0
|
|
262
|
+
try:
|
|
263
|
+
vw = float(GWconfig.wall_velocity)
|
|
264
|
+
except:
|
|
265
|
+
raise ValueError("wall_velocity must be 'LTE' or a float. " +
|
|
266
|
+
"Not: ", GWconfig.wall_velocity, "!")
|
|
267
|
+
if vw <= 0.0 or vw > 1.0:
|
|
268
|
+
raise ValueError("Wall velocity must be 0 < vw <= 1.0." +
|
|
269
|
+
"Not ", vw, "!")
|
|
270
|
+
else:
|
|
271
|
+
derived["v_wall"] = vw
|
|
272
|
+
|
|
273
|
+
def _ensure_sound_speed(self, ctx: TransitionContext, T: float) -> None:
|
|
274
|
+
"""Populate sound speed values when requested."""
|
|
275
|
+
if "c_s" not in ctx.derived_param_names:
|
|
276
|
+
return
|
|
277
|
+
derived = ctx.derived_params
|
|
278
|
+
GWconfig = ctx.GWconfig
|
|
279
|
+
if ctx.verbose:
|
|
280
|
+
print("Calculating sound speed...")
|
|
281
|
+
if GWconfig.sound_speed == "compute":
|
|
282
|
+
hydr = Hydrodynamics(ctx.pot, ctx.phase_symmetric, ctx.phase_broken, ctx.verbose)
|
|
283
|
+
c_sb = hydr.calc_cs(T, sym=False)
|
|
284
|
+
c_ss = hydr.calc_cs(T, sym=True)
|
|
285
|
+
derived["c_s"] = c_sb
|
|
286
|
+
derived["c_s_sym"] = c_ss
|
|
287
|
+
derived["c_s_bro"] = c_sb
|
|
288
|
+
else:
|
|
289
|
+
cs = 0.0
|
|
290
|
+
try:
|
|
291
|
+
cs = float(GWconfig.sound_speed)
|
|
292
|
+
except:
|
|
293
|
+
raise NotImplementedError(
|
|
294
|
+
"The GWconfig.sound_speed option is not implemented yet: "
|
|
295
|
+
+ GWconfig.sound_speed
|
|
296
|
+
)
|
|
297
|
+
if cs <= 1.0 and cs > 0:
|
|
298
|
+
derived["c_s"] = cs
|
|
299
|
+
derived["c_s_sym"] = cs
|
|
300
|
+
derived["c_s_bro"] = cs
|
|
301
|
+
else:
|
|
302
|
+
raise ValueError("Speed of sound must be 0 < cs <= 1." +
|
|
303
|
+
" Not ", cs, "!")
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _compute_transition_strength(self, ctx: TransitionContext) -> float:
|
|
307
|
+
"""Return alpha_theta at nucleation and handle logging."""
|
|
308
|
+
weak_threshold = ctx.PercolationConf.weak_threshold
|
|
309
|
+
_, alpha_theta_nuc, _, _, _, _ = calcAlphas(
|
|
310
|
+
ctx.Tnuc, ctx.pot, ctx.phase_symmetric, ctx.phase_broken,
|
|
311
|
+
verbose=ctx.verbose
|
|
312
|
+
)
|
|
313
|
+
if ctx.verbose:
|
|
314
|
+
print("alpha at nucleation =", np.squeeze(alpha_theta_nuc))
|
|
315
|
+
return np.squeeze(alpha_theta_nuc)
|
|
316
|
+
|
|
317
|
+
def _compute_percolation(
|
|
318
|
+
self,
|
|
319
|
+
ctx: TransitionContext,
|
|
320
|
+
alpha_theta_nuc: float,
|
|
321
|
+
rtol: float,
|
|
322
|
+
nAction: int,
|
|
323
|
+
) -> PercolationResult:
|
|
324
|
+
"""Either reuse nucleation data or perform the percolation computation."""
|
|
325
|
+
pot = ctx.pot
|
|
326
|
+
derived = ctx.derived_params
|
|
327
|
+
verbose = ctx.verbose
|
|
328
|
+
GWconfig = ctx.GWconfig
|
|
329
|
+
weak_threshold = ctx.PercolationConf.weak_threshold
|
|
330
|
+
|
|
331
|
+
if alpha_theta_nuc < weak_threshold:
|
|
332
|
+
if verbose:
|
|
333
|
+
print(
|
|
334
|
+
"alpha at nucleation is too small (alpha =",
|
|
335
|
+
alpha_theta_nuc,
|
|
336
|
+
"<",
|
|
337
|
+
weak_threshold,
|
|
338
|
+
"), using Tnuc as Treh",
|
|
339
|
+
)
|
|
340
|
+
derived["Treh_SM_GeV"] = ctx.Tnuc * pot.conversionFactor
|
|
341
|
+
derived["WARNING:too_weak_to_compute_perc"] = True
|
|
342
|
+
derived["WARNING:no_perc_splines"] = True
|
|
343
|
+
return PercolationResult(
|
|
344
|
+
Tperc=ctx.Tnuc,
|
|
345
|
+
TSYM=None,
|
|
346
|
+
H=None,
|
|
347
|
+
P=None,
|
|
348
|
+
TBRO=None,
|
|
349
|
+
S=None,
|
|
350
|
+
Pint=None,
|
|
351
|
+
Sint=None,
|
|
352
|
+
Hint=None,
|
|
353
|
+
Pexpint=None,
|
|
354
|
+
soundSpSqint=None,
|
|
355
|
+
scalef_r_int=None,
|
|
356
|
+
TBROint=None,
|
|
357
|
+
successful=False,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
if verbose:
|
|
361
|
+
msg = (
|
|
362
|
+
f"alpha at nucleation is large enough "
|
|
363
|
+
f"(alpha = {alpha_theta_nuc:.3e} > {weak_threshold:.3e}). "
|
|
364
|
+
"Continue with percolation computation."
|
|
365
|
+
)
|
|
366
|
+
print(msg)
|
|
367
|
+
|
|
368
|
+
try:
|
|
369
|
+
Tperc, TSYM, H, P, TBRO, S, P_exp, scalef_r, soundSpSq = calcPercAndEvolve(
|
|
370
|
+
ctx.outdict,
|
|
371
|
+
ctx.Tnuc,
|
|
372
|
+
ctx.phase_symmetric,
|
|
373
|
+
ctx.phase_broken,
|
|
374
|
+
pot,
|
|
375
|
+
rtol=rtol,
|
|
376
|
+
nAction=nAction,
|
|
377
|
+
verbose=verbose,
|
|
378
|
+
vw=ctx.derived_params.get("v_wall", 1.0),
|
|
379
|
+
)
|
|
380
|
+
except Exception as err:
|
|
381
|
+
if verbose:
|
|
382
|
+
print("Fatal error in calcPercAndEvolve: ", err)
|
|
383
|
+
raise
|
|
384
|
+
|
|
385
|
+
try:
|
|
386
|
+
if verbose:
|
|
387
|
+
print("Calculating percolation splines...")
|
|
388
|
+
finite_mask = np.isfinite(P)
|
|
389
|
+
Pint = interpolate.interp1d(
|
|
390
|
+
TSYM[finite_mask],
|
|
391
|
+
P[finite_mask],
|
|
392
|
+
kind="cubic",
|
|
393
|
+
fill_value=(0, 1),
|
|
394
|
+
bounds_error=False,
|
|
395
|
+
)
|
|
396
|
+
Pexpint = interpolate.interp1d(
|
|
397
|
+
TSYM[finite_mask],
|
|
398
|
+
P_exp[finite_mask],
|
|
399
|
+
kind="cubic",
|
|
400
|
+
fill_value=(0, 1),
|
|
401
|
+
bounds_error=False,
|
|
402
|
+
)
|
|
403
|
+
soundSqSqint = interpolate.interp1d(
|
|
404
|
+
TSYM[finite_mask],
|
|
405
|
+
soundSpSq[finite_mask],
|
|
406
|
+
kind="cubic",
|
|
407
|
+
bounds_error=False,
|
|
408
|
+
)
|
|
409
|
+
scalef_r_int = interpolate.interp1d(
|
|
410
|
+
TSYM[finite_mask],
|
|
411
|
+
scalef_r[finite_mask],
|
|
412
|
+
kind="cubic",
|
|
413
|
+
bounds_error=False,
|
|
414
|
+
)
|
|
415
|
+
Sint = interpolate.interp1d(
|
|
416
|
+
TSYM[np.isfinite(S)],
|
|
417
|
+
S[np.isfinite(S)],
|
|
418
|
+
kind="cubic",
|
|
419
|
+
fill_value=(-np.inf, np.inf),
|
|
420
|
+
bounds_error=False,
|
|
421
|
+
)
|
|
422
|
+
Hint = interpolate.interp1d(TSYM, H, kind="cubic")
|
|
423
|
+
TBROint = interpolate.interp1d(TSYM, TBRO, kind="cubic")
|
|
424
|
+
except Exception as err:
|
|
425
|
+
derived["WARNING:no_perc_splines"] = True
|
|
426
|
+
if verbose:
|
|
427
|
+
print("Error in computing percolation splines: ", err)
|
|
428
|
+
msg = (
|
|
429
|
+
"WARNING: Cannot calculate the splines. Continue with the "
|
|
430
|
+
"percolation temperature, but no splines will be available "
|
|
431
|
+
"for further calculations."
|
|
432
|
+
)
|
|
433
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
434
|
+
Pint = Sint = Hint = TBROint = Pexpint = soundSqSqint = scalef_r_int = None
|
|
435
|
+
|
|
436
|
+
return PercolationResult(
|
|
437
|
+
Tperc=Tperc,
|
|
438
|
+
TSYM=TSYM,
|
|
439
|
+
H=H,
|
|
440
|
+
P=P,
|
|
441
|
+
TBRO=TBRO,
|
|
442
|
+
S=S,
|
|
443
|
+
Pint=Pint,
|
|
444
|
+
Sint=Sint,
|
|
445
|
+
Hint=Hint,
|
|
446
|
+
Pexpint=Pexpint,
|
|
447
|
+
soundSpSqint=soundSqSqint,
|
|
448
|
+
scalef_r_int=scalef_r_int,
|
|
449
|
+
TBROint=TBROint,
|
|
450
|
+
successful=True,
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
def _populate_temperature_observables(
|
|
454
|
+
self,
|
|
455
|
+
ctx: TransitionContext,
|
|
456
|
+
percolation: PercolationResult,
|
|
457
|
+
) -> None:
|
|
458
|
+
"""Fill temperature-related entries in the derived parameters."""
|
|
459
|
+
derived = ctx.derived_params
|
|
460
|
+
pot = ctx.pot
|
|
461
|
+
|
|
462
|
+
if "Tperc_SM_GeV" in ctx.derived_param_names:
|
|
463
|
+
if ctx.verbose:
|
|
464
|
+
print("Calculating percolation temperature...")
|
|
465
|
+
derived["Tperc"] = percolation.Tperc
|
|
466
|
+
derived["Tperc_SM_GeV"] = percolation.Tperc * pot.conversionFactor
|
|
467
|
+
|
|
468
|
+
if "Tcrit_SM_GeV" in ctx.derived_param_names:
|
|
469
|
+
if ctx.verbose:
|
|
470
|
+
print("Calculating critical temperature...")
|
|
471
|
+
derived["Tcrit_SM_GeV"] = ctx.tr.Tcrit * pot.conversionFactor
|
|
472
|
+
|
|
473
|
+
if "xi_crit" in ctx.derived_param_names:
|
|
474
|
+
if ctx.verbose:
|
|
475
|
+
print("Calculating critical vev over temperature...")
|
|
476
|
+
T_crit = ctx.tr.Tcrit
|
|
477
|
+
vev_crit = np.sqrt(np.sum(ctx.phase_broken.valAt(T_crit) ** 2))
|
|
478
|
+
derived["xi_crit"] = vev_crit / T_crit
|
|
479
|
+
|
|
480
|
+
if "Tnuc_SM_GeV" in ctx.derived_param_names:
|
|
481
|
+
if ctx.verbose:
|
|
482
|
+
print("Calculating nucleation temperature...")
|
|
483
|
+
derived["Tnuc_SM_GeV"] = ctx.tr.Tnuc * pot.conversionFactor
|
|
484
|
+
|
|
485
|
+
if "Treh_SM_GeV" in ctx.derived_param_names:
|
|
486
|
+
if ctx.verbose:
|
|
487
|
+
print("Calculating reheating temperature...")
|
|
488
|
+
if derived.get("WARNING:no_perc_splines", False):
|
|
489
|
+
if ctx.verbose:
|
|
490
|
+
msg = (
|
|
491
|
+
"WARNING: Set Treh_SM_GeV to Tperc_SM_GeV "
|
|
492
|
+
"because no percolation splines were found."
|
|
493
|
+
)
|
|
494
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
495
|
+
Treh = percolation.Tperc
|
|
496
|
+
else:
|
|
497
|
+
Treh = percolation.TBROint(percolation.Tperc) if percolation.TBROint else percolation.Tperc
|
|
498
|
+
derived["Treh"] = Treh
|
|
499
|
+
derived["Treh_SM_GeV"] = Treh * pot.conversionFactor
|
|
500
|
+
|
|
501
|
+
def _compute_alpha_parameters(
|
|
502
|
+
self,
|
|
503
|
+
ctx: TransitionContext,
|
|
504
|
+
percolation: PercolationResult,
|
|
505
|
+
) -> None:
|
|
506
|
+
"""Compute alpha-related quantities if requested."""
|
|
507
|
+
if "alpha" not in ctx.derived_param_names:
|
|
508
|
+
return
|
|
509
|
+
if ctx.verbose:
|
|
510
|
+
print("Calculating alpha parameters...")
|
|
511
|
+
alpha_p, alpha_theta, alpha_e, alpha_hyd, alpha_inf, alpha_eq = calcAlphas(
|
|
512
|
+
percolation.Tperc, ctx.pot, ctx.phase_symmetric, ctx.phase_broken,
|
|
513
|
+
verbose=ctx.verbose
|
|
514
|
+
)
|
|
515
|
+
derived = ctx.derived_params
|
|
516
|
+
derived["alpha"] = np.squeeze(alpha_theta)
|
|
517
|
+
derived["alpha_theta"] = np.squeeze(alpha_theta)
|
|
518
|
+
derived["alpha_p"] = np.squeeze(alpha_p)
|
|
519
|
+
derived["alpha_e"] = np.squeeze(alpha_e)
|
|
520
|
+
derived["alpha_hyd"] = np.squeeze(alpha_hyd)
|
|
521
|
+
derived["alpha_inf"] = np.squeeze(alpha_inf)
|
|
522
|
+
derived["alpha_eq"] = np.squeeze(alpha_eq)
|
|
523
|
+
|
|
524
|
+
def _compute_beta_and_separation(
|
|
525
|
+
self,
|
|
526
|
+
ctx: TransitionContext,
|
|
527
|
+
percolation: PercolationResult,
|
|
528
|
+
tmin: float,
|
|
529
|
+
tmax: float,
|
|
530
|
+
) -> None:
|
|
531
|
+
"""Populate beta/H variants, RH and Tf if configured."""
|
|
532
|
+
derived = ctx.derived_params
|
|
533
|
+
pot = ctx.pot
|
|
534
|
+
verbose = ctx.verbose
|
|
535
|
+
outdict = ctx.outdict
|
|
536
|
+
phase_symmetric = ctx.phase_symmetric
|
|
537
|
+
phase_broken = ctx.phase_broken
|
|
538
|
+
|
|
539
|
+
if "betaH_S3_approx" in ctx.derived_param_names:
|
|
540
|
+
if verbose:
|
|
541
|
+
print("Calculating beta/H (approximation through derivative of bounce action)...")
|
|
542
|
+
derived["betaH_S3_approx"] = calc_betaH_S3_approx(
|
|
543
|
+
percolation.Tperc, outdict, pot, phase_symmetric, phase_broken, tmin, tmax, verbose=verbose
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
if "RH" in ctx.derived_param_names:
|
|
547
|
+
if verbose:
|
|
548
|
+
print("Calculating mean bubble separation...")
|
|
549
|
+
if (
|
|
550
|
+
derived.get("WARNING:no_perc_splines", False)
|
|
551
|
+
or percolation.Sint is None
|
|
552
|
+
or percolation.TSYM is None
|
|
553
|
+
):
|
|
554
|
+
if verbose:
|
|
555
|
+
msg = (
|
|
556
|
+
"WARNING: Set RH to Nan "
|
|
557
|
+
"because no percolation splines were found."
|
|
558
|
+
)
|
|
559
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
560
|
+
derived["RH"] = np.nan
|
|
561
|
+
else:
|
|
562
|
+
Rsep = calcMeanBubbleSeparation(
|
|
563
|
+
percolation.Tperc,
|
|
564
|
+
percolation.TSYM[0],
|
|
565
|
+
percolation.Sint,
|
|
566
|
+
percolation.Pint,
|
|
567
|
+
percolation.Hint,
|
|
568
|
+
)
|
|
569
|
+
Rsep_exp = calcMeanBubbleSeparationwExp(
|
|
570
|
+
percolation.Tperc,
|
|
571
|
+
percolation.TSYM[0],
|
|
572
|
+
percolation.Sint,
|
|
573
|
+
percolation.Pexpint,
|
|
574
|
+
percolation.Hint,
|
|
575
|
+
percolation.soundSpSqint,
|
|
576
|
+
percolation.scalef_r_int,
|
|
577
|
+
)
|
|
578
|
+
RsepHperc = Rsep * percolation.Hint(percolation.Tperc)
|
|
579
|
+
derived["RH"] = RsepHperc
|
|
580
|
+
|
|
581
|
+
# This combines the dark-sector contribution with the SM bath and
|
|
582
|
+
# therefore assumes a DS + SM setup.
|
|
583
|
+
if "g_eff_tot_reh" in ctx.derived_param_names:
|
|
584
|
+
if verbose:
|
|
585
|
+
print("Calculating g_eff_tot_reh...")
|
|
586
|
+
bosons = pot.boson_massSq(ctx.phase_broken.valAt(percolation.Tperc), percolation.Tperc)
|
|
587
|
+
fermions = pot.fermion_massSq(ctx.phase_broken.valAt(percolation.Tperc))
|
|
588
|
+
gefftotreh = td.e_geffDS(
|
|
589
|
+
bosons*(~pot.mass_spectrum.is_SM_bosons),
|
|
590
|
+
fermions*(~pot.mass_spectrum.is_SM_fermions),
|
|
591
|
+
percolation.Tperc,
|
|
592
|
+
) + td.e_geffSM(percolation.Tperc, pot.conversionFactor)
|
|
593
|
+
derived["g_eff_tot_reh"] = gefftotreh
|
|
594
|
+
|
|
595
|
+
# This combines the dark-sector contribution with the SM bath and
|
|
596
|
+
# therefore assumes a DS + SM setup.
|
|
597
|
+
if "h_eff_tot_reh" in ctx.derived_param_names:
|
|
598
|
+
if verbose:
|
|
599
|
+
print("Calculating h_eff_tot_reh...")
|
|
600
|
+
bosons = pot.boson_massSq(ctx.phase_broken.valAt(percolation.Tperc), percolation.Tperc)
|
|
601
|
+
fermions = pot.fermion_massSq(ctx.phase_broken.valAt(percolation.Tperc))
|
|
602
|
+
hefftotreh = td.s_geffDS(
|
|
603
|
+
bosons*(~pot.mass_spectrum.is_SM_bosons),
|
|
604
|
+
fermions*(~pot.mass_spectrum.is_SM_fermions),
|
|
605
|
+
percolation.Tperc,
|
|
606
|
+
) + td.s_geffSM(percolation.Tperc, pot.conversionFactor)
|
|
607
|
+
derived["h_eff_tot_reh"] = hefftotreh
|
|
608
|
+
|
|
609
|
+
if "g0" in ctx.derived_param_names:
|
|
610
|
+
derived["g0"] = 2
|
|
611
|
+
|
|
612
|
+
if "h0" in ctx.derived_param_names:
|
|
613
|
+
derived["h0"] = 3.91
|
|
614
|
+
|
|
615
|
+
if (
|
|
616
|
+
"betaH_S3" in ctx.derived_param_names
|
|
617
|
+
or "betaH_RH" in ctx.derived_param_names
|
|
618
|
+
or "Tf_SM_GeV" in ctx.derived_param_names
|
|
619
|
+
):
|
|
620
|
+
self._populate_beta_related(
|
|
621
|
+
ctx,
|
|
622
|
+
percolation,
|
|
623
|
+
tmin,
|
|
624
|
+
tmax,
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
def _populate_beta_related(
|
|
628
|
+
self,
|
|
629
|
+
ctx: TransitionContext,
|
|
630
|
+
percolation: PercolationResult,
|
|
631
|
+
tmin: float,
|
|
632
|
+
tmax: float,
|
|
633
|
+
) -> None:
|
|
634
|
+
"""Gather betaH variants and Tf once percolation data is available."""
|
|
635
|
+
derived = ctx.derived_params
|
|
636
|
+
verbose = ctx.verbose
|
|
637
|
+
pot = ctx.pot
|
|
638
|
+
|
|
639
|
+
if "betaH_S3" in ctx.derived_param_names:
|
|
640
|
+
if verbose:
|
|
641
|
+
print("Calculating betaH_S3 (through the percolation splines)...")
|
|
642
|
+
if derived.get("WARNING:no_perc_splines", False) or percolation.Sint is None:
|
|
643
|
+
if verbose:
|
|
644
|
+
msg = (
|
|
645
|
+
"WARNING: Approximate betaH_S3 only by using calc_betaH_S3_approx "
|
|
646
|
+
"because no percolation splines were found."
|
|
647
|
+
)
|
|
648
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
649
|
+
|
|
650
|
+
derived["betaH_S3"] = calc_betaH_S3_approx(
|
|
651
|
+
percolation.Tperc,
|
|
652
|
+
ctx.outdict,
|
|
653
|
+
ctx.pot,
|
|
654
|
+
ctx.phase_symmetric,
|
|
655
|
+
ctx.phase_broken,
|
|
656
|
+
tmin,
|
|
657
|
+
tmax,
|
|
658
|
+
verbose=verbose,
|
|
659
|
+
)
|
|
660
|
+
else:
|
|
661
|
+
derived["betaH_S3"] = calc_betaH_S3(
|
|
662
|
+
percolation.Tperc,
|
|
663
|
+
percolation.Sint,
|
|
664
|
+
ctx.outdict,
|
|
665
|
+
ctx.pot,
|
|
666
|
+
ctx.phase_symmetric,
|
|
667
|
+
ctx.phase_broken,
|
|
668
|
+
verbose,
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
if "betaH_RH" in ctx.derived_param_names:
|
|
672
|
+
if derived.get("WARNING:no_perc_splines", False):
|
|
673
|
+
if verbose:
|
|
674
|
+
msg = (
|
|
675
|
+
"Set betaH_RH to np.nan "
|
|
676
|
+
"because no percolation splines were found."
|
|
677
|
+
)
|
|
678
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
679
|
+
derived["betaH_RH"] = np.nan
|
|
680
|
+
else:
|
|
681
|
+
f_perc = ctx.PercolationConf.f_perc
|
|
682
|
+
derived["betaH_RH"] = (
|
|
683
|
+
(8 * np.pi) ** (1 / 3)
|
|
684
|
+
/ derived["RH"]
|
|
685
|
+
* max(derived.get("v_wall", 1.0), derived.get("c_s", 1 / np.sqrt(3)))
|
|
686
|
+
* (1 / f_perc) ** (1 / 3)
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
if "Tf_SM_GeV" in ctx.derived_param_names:
|
|
690
|
+
if verbose:
|
|
691
|
+
print("Calculating Tf_SM_GeV...")
|
|
692
|
+
if (
|
|
693
|
+
derived.get("WARNING:no_perc_splines", False)
|
|
694
|
+
or percolation.Pint is None
|
|
695
|
+
or percolation.TSYM is None
|
|
696
|
+
):
|
|
697
|
+
if verbose:
|
|
698
|
+
msg = (
|
|
699
|
+
"Set Tf_SM_GeV to np.nan because no "
|
|
700
|
+
"percolation splines were found."
|
|
701
|
+
)
|
|
702
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
703
|
+
Tf_val = np.nan
|
|
704
|
+
else:
|
|
705
|
+
try:
|
|
706
|
+
Tf_val = calcTf(
|
|
707
|
+
percolation.Tperc,
|
|
708
|
+
percolation.TSYM[-1],
|
|
709
|
+
percolation.Pint,
|
|
710
|
+
pot,
|
|
711
|
+
verbose=verbose,
|
|
712
|
+
)
|
|
713
|
+
except errors.PercolationError as err:
|
|
714
|
+
if verbose:
|
|
715
|
+
msg = (
|
|
716
|
+
"Could not compute the temperature at which the "
|
|
717
|
+
"transition ends (Tf_SM_GeV). Set it to np.nan instead."
|
|
718
|
+
)
|
|
719
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
720
|
+
console.print("Error message: ", err)
|
|
721
|
+
Tf_val = np.nan
|
|
722
|
+
derived["Tf_SM_GeV"] = Tf_val * pot.conversionFactor if np.isfinite(Tf_val) else np.nan
|
|
723
|
+
|
|
724
|
+
def _compute_kappa_parameters(
|
|
725
|
+
self,
|
|
726
|
+
ctx: TransitionContext,
|
|
727
|
+
percolation: PercolationResult
|
|
728
|
+
) -> None:
|
|
729
|
+
"""Calculate kappa parameters if required.
|
|
730
|
+
|
|
731
|
+
Parameters
|
|
732
|
+
----------
|
|
733
|
+
ctx : TransitionContext
|
|
734
|
+
percolation : PercolationResult
|
|
735
|
+
|
|
736
|
+
Returns
|
|
737
|
+
-------
|
|
738
|
+
None.
|
|
739
|
+
"""
|
|
740
|
+
names = ctx.derived_param_names
|
|
741
|
+
if not {"kappa_phi", "kappa_sw", "kappa_turb"} & set(names):
|
|
742
|
+
return
|
|
743
|
+
if ctx.verbose:
|
|
744
|
+
print("Calculating kappa parameters...")
|
|
745
|
+
_, alpha_thetaP, _, alpha_hydP, alpha_infP, alpha_eqP = calcAlphas(
|
|
746
|
+
percolation.Tperc, ctx.pot, ctx.phase_symmetric, ctx.phase_broken,
|
|
747
|
+
verbose=ctx.verbose
|
|
748
|
+
)
|
|
749
|
+
# Compute the initial bubble radius R0. We take it to be
|
|
750
|
+
# the radius of the bubble at the nucleation temperature,
|
|
751
|
+
# which is the radius at which the field is halfway
|
|
752
|
+
# between the start and endpoint of the transition. Note
|
|
753
|
+
# that the endpoint of the transition is not necessarily
|
|
754
|
+
# the broken phase minimum, rather the point from which on
|
|
755
|
+
# the field just rolls down to the broken phase minimum, i.e.
|
|
756
|
+
# the endpoint in the instanton solution.
|
|
757
|
+
|
|
758
|
+
# this is the dictionary with the transition
|
|
759
|
+
# parameters at the nucleation temperature
|
|
760
|
+
instanton = ctx.tr.instanton
|
|
761
|
+
R_, phi_ = instanton.profile1D.R, instanton.profile1D.Phi
|
|
762
|
+
phi_middle = (phi_[0] + phi_[-1]) / 2
|
|
763
|
+
idx = np.argmin(np.abs(phi_ - phi_middle))
|
|
764
|
+
|
|
765
|
+
# this is the radius at which the field is halfway between the
|
|
766
|
+
# start and endpoint of the transition
|
|
767
|
+
R0 = R_[idx]
|
|
768
|
+
|
|
769
|
+
RH = ctx.derived_params.get("RH")
|
|
770
|
+
if RH is None:
|
|
771
|
+
overlap_tmin = max(float(ctx.phase_symmetric.Tmin), float(ctx.phase_broken.Tmin))
|
|
772
|
+
overlap_tmax = min(float(ctx.phase_symmetric.Tmax), float(ctx.phase_broken.Tmax))
|
|
773
|
+
betaH_approx = calcBetaHapprox(
|
|
774
|
+
percolation.Tperc,
|
|
775
|
+
ctx.outdict,
|
|
776
|
+
ctx.pot,
|
|
777
|
+
ctx.phase_symmetric,
|
|
778
|
+
ctx.phase_broken,
|
|
779
|
+
overlap_tmin,
|
|
780
|
+
overlap_tmax,
|
|
781
|
+
verbose=ctx.verbose,
|
|
782
|
+
)
|
|
783
|
+
f_perc = ctx.PercolationConf.f_perc
|
|
784
|
+
RH = (8 * np.pi / f_perc) ** (1 / 3) / betaH_approx * max(
|
|
785
|
+
ctx.derived_params.get("v_wall", 1.0),
|
|
786
|
+
ctx.derived_params.get("c_s", 1 / np.sqrt(3))
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
# Bubble size at time of collision (percolation)
|
|
790
|
+
Hstar = HubbleParameter(
|
|
791
|
+
energyDensity(ctx.pot, ctx.phase_symmetric, percolation.Tperc),
|
|
792
|
+
ctx.pot.conversionFactor
|
|
793
|
+
)
|
|
794
|
+
Rstar = RH / Hstar
|
|
795
|
+
|
|
796
|
+
kappa_phi, kappa_sw, kappa_turb = calc_kappas(
|
|
797
|
+
alpha_hydP,
|
|
798
|
+
alpha_infP,
|
|
799
|
+
alpha_eqP,
|
|
800
|
+
ctx.derived_params.get("v_wall", 1.0),
|
|
801
|
+
ctx.derived_params.get("c_s", 1 / np.sqrt(3)),
|
|
802
|
+
Rstar,
|
|
803
|
+
R0,
|
|
804
|
+
ctx.GWconfig,
|
|
805
|
+
)
|
|
806
|
+
ctx.derived_params["kappa_phi"] = kappa_phi
|
|
807
|
+
ctx.derived_params["kappa_sw"] = kappa_sw
|
|
808
|
+
ctx.derived_params["kappa_turb"] = kappa_turb
|
|
809
|
+
|
|
810
|
+
def _finalize_results(self, ctx: TransitionContext) -> dict:
|
|
811
|
+
"""Ensure all requested parameters are present and return dict."""
|
|
812
|
+
derived = ctx.derived_params
|
|
813
|
+
beta_S3 = derived.get("betaH_S3", np.nan)
|
|
814
|
+
beta_RH = derived.get("betaH_RH", np.nan)
|
|
815
|
+
|
|
816
|
+
if "WARNING:betaH_small" in ctx.derived_param_names:
|
|
817
|
+
derived["WARNING:betaH_small"] = derived.get("betaH_RH", np.inf) < 10
|
|
818
|
+
|
|
819
|
+
if "WARNING:betaH_very_small" in ctx.derived_param_names:
|
|
820
|
+
derived["WARNING:betaH_very_small"] = derived.get("betaH_RH", np.inf) < 3
|
|
821
|
+
|
|
822
|
+
if "WARNING:nucleationRate_nonexponential" in ctx.derived_param_names:
|
|
823
|
+
derived["WARNING:nucleationRate_nonexponential"] = (
|
|
824
|
+
np.isfinite(beta_S3) and beta_S3 < 0
|
|
825
|
+
)
|
|
826
|
+
|
|
827
|
+
if "WARNING:betaH_nonfinite" in ctx.derived_param_names:
|
|
828
|
+
derived["WARNING:betaH_nonfinite"] = (
|
|
829
|
+
not np.isfinite(beta_S3) or not np.isfinite(beta_RH)
|
|
830
|
+
)
|
|
831
|
+
|
|
832
|
+
if "WARNING:betaH_mismatch" in ctx.derived_param_names:
|
|
833
|
+
mismatch = False
|
|
834
|
+
if np.isfinite(beta_S3) and np.isfinite(beta_RH):
|
|
835
|
+
abs_beta_S3 = abs(beta_S3)
|
|
836
|
+
abs_beta_RH = abs(beta_RH)
|
|
837
|
+
if abs_beta_S3 == 0 or abs_beta_RH == 0:
|
|
838
|
+
mismatch = not np.isclose(abs_beta_S3, abs_beta_RH)
|
|
839
|
+
else:
|
|
840
|
+
mismatch = max(
|
|
841
|
+
abs_beta_RH / abs_beta_S3,
|
|
842
|
+
abs_beta_S3 / abs_beta_RH,
|
|
843
|
+
) >= 10
|
|
844
|
+
derived["WARNING:betaH_mismatch"] = mismatch
|
|
845
|
+
|
|
846
|
+
if "WARNING:not_T0_global_min" in ctx.derived_param_names:
|
|
847
|
+
# This flag is set in the check_T0_global_min function,
|
|
848
|
+
# when checking all transitions after initialization.
|
|
849
|
+
derived["WARNING:not_T0_global_min"] = False
|
|
850
|
+
|
|
851
|
+
# Check if there are any names in derived_param_names which are not
|
|
852
|
+
# in the derived_params_dict
|
|
853
|
+
for name in ctx.derived_param_names:
|
|
854
|
+
if name not in derived:
|
|
855
|
+
msg = (
|
|
856
|
+
f"{name} not found in derived_params_dict. "
|
|
857
|
+
"It might be that this variable still needs to be implemented. "
|
|
858
|
+
"It is added to the dictionary with value NaN."
|
|
859
|
+
)
|
|
860
|
+
console.print(f"[bold yellow]WARNING:[/bold yellow] {msg}")
|
|
861
|
+
derived[name] = np.nan
|
|
862
|
+
|
|
863
|
+
return derived
|
|
864
|
+
|
|
865
|
+
def computeTransitionObservables_one_transition(self, tr : TransitionInfo,
|
|
866
|
+
rtol=1e-4, nAction=50):
|
|
867
|
+
"""Calculate the GW observables after the phase tracing and the
|
|
868
|
+
computation of the nucleation temperature have been performed.
|
|
869
|
+
This function assumes kinetic equilibrium between the dark sector and
|
|
870
|
+
the SM.
|
|
871
|
+
|
|
872
|
+
Parameters
|
|
873
|
+
----------
|
|
874
|
+
tr : TransitionInfo
|
|
875
|
+
The transition information for which to compute observables.
|
|
876
|
+
rtol : float, optional
|
|
877
|
+
Relative tolerance for the computation. Default is 1e-4.
|
|
878
|
+
nAction : int, optional
|
|
879
|
+
Number of action points to consider. Default is 50.
|
|
880
|
+
Returns
|
|
881
|
+
----------
|
|
882
|
+
GWparams : tuple (float)
|
|
883
|
+
Dictionary with the GW parameters."""
|
|
884
|
+
|
|
885
|
+
ctx = self._initialize_transition_context(tr)
|
|
886
|
+
if ctx.verbose:
|
|
887
|
+
print(
|
|
888
|
+
"\nStart calculating GW observables for transition from phase",
|
|
889
|
+
tr.high_phase,
|
|
890
|
+
"to phase",
|
|
891
|
+
tr.low_phase,
|
|
892
|
+
"at Tnuc =",
|
|
893
|
+
tr.Tnuc * self.pot.conversionFactor,
|
|
894
|
+
"GeV",
|
|
895
|
+
)
|
|
896
|
+
|
|
897
|
+
tmin = max(float(ctx.phase_symmetric.Tmin), float(ctx.phase_broken.Tmin))
|
|
898
|
+
tmax = min(float(ctx.phase_symmetric.Tmax), float(ctx.phase_broken.Tmax))
|
|
899
|
+
if tmin >= tmax:
|
|
900
|
+
raise errors.PercolationError(
|
|
901
|
+
"No overlapping temperature interval between traced phases: "
|
|
902
|
+
f"Tsym in [{ctx.phase_symmetric.Tmin:.8g}, {ctx.phase_symmetric.Tmax:.8g}], "
|
|
903
|
+
f"Tbro in [{ctx.phase_broken.Tmin:.8g}, {ctx.phase_broken.Tmax:.8g}]."
|
|
904
|
+
)
|
|
905
|
+
|
|
906
|
+
alpha_theta_nuc = self._compute_transition_strength(ctx)
|
|
907
|
+
percolation = self._compute_percolation(ctx, alpha_theta_nuc, rtol, nAction)
|
|
908
|
+
|
|
909
|
+
self._ensure_wall_velocity(ctx, percolation.Tperc)
|
|
910
|
+
self._ensure_sound_speed(ctx, percolation.Tperc)
|
|
911
|
+
|
|
912
|
+
self._populate_temperature_observables(ctx, percolation)
|
|
913
|
+
self._compute_alpha_parameters(ctx, percolation)
|
|
914
|
+
self._compute_beta_and_separation(ctx, percolation, tmin, tmax)
|
|
915
|
+
self._compute_kappa_parameters(ctx, percolation)
|
|
916
|
+
|
|
917
|
+
derived = ctx.derived_params
|
|
918
|
+
if "D" in ctx.derived_param_names:
|
|
919
|
+
derived["D"] = 1
|
|
920
|
+
if "step" in ctx.derived_param_names:
|
|
921
|
+
derived["step"] = ctx.tr.step
|
|
922
|
+
if "total_steps" in ctx.derived_param_names:
|
|
923
|
+
derived["total_steps"] = ctx.tr.total_steps
|
|
924
|
+
|
|
925
|
+
return self._finalize_results(ctx), percolation, ctx.outdict
|
|
926
|
+
|
|
927
|
+
def __iter__(self):
|
|
928
|
+
"""Enable iteration over the derived observables dictionary."""
|
|
929
|
+
return iter(self.transitionObservables)
|
|
930
|
+
|
|
931
|
+
def __getitem__(self, key: str):
|
|
932
|
+
"""Allow dictionary-style access to an individual transition."""
|
|
933
|
+
return self.transitionObservables[key]
|
|
934
|
+
|
|
935
|
+
def __len__(self):
|
|
936
|
+
"""Return the number of transitions for which observables were computed."""
|
|
937
|
+
return len(self.transitionObservables)
|
|
938
|
+
|
|
939
|
+
def keys(self):
|
|
940
|
+
"""Expose the transition keys."""
|
|
941
|
+
return self.transitionObservables.keys()
|
|
942
|
+
|
|
943
|
+
def items(self):
|
|
944
|
+
"""Return key/value pairs of the transition observables."""
|
|
945
|
+
return self.transitionObservables.items()
|
|
946
|
+
|
|
947
|
+
def printDerivedParams(self, derived_param_names):
|
|
948
|
+
"""Print a rich-formatted table of the derived parameters per transition."""
|
|
949
|
+
nTransitions = len(self.transitions)
|
|
950
|
+
print("\nComputed thermodynamic quantities for", nTransitions, "transition(s):\n")
|
|
951
|
+
for i, tr in enumerate(self.transitions):
|
|
952
|
+
if tr.type == 1:
|
|
953
|
+
derived_params_dict = self.transitionObservables[i]
|
|
954
|
+
table = rich.table.Table(
|
|
955
|
+
title=f"Transition {i+1}: First-order phase transition",
|
|
956
|
+
title_justify="left",
|
|
957
|
+
box=rich.box.ROUNDED,
|
|
958
|
+
)
|
|
959
|
+
table.add_column("Parameter", style="cyan", no_wrap=True)
|
|
960
|
+
table.add_column("Value", style="orange1")
|
|
961
|
+
for j, name in enumerate(derived_param_names):
|
|
962
|
+
table.add_row(name, f"{derived_params_dict[name]:.10e}")
|
|
963
|
+
console.print(table)
|
|
964
|
+
|
|
965
|
+
if tr.type == 2:
|
|
966
|
+
table = rich.table.Table(
|
|
967
|
+
title=f"Transition {i+1}: Second-order phase transition",
|
|
968
|
+
title_justify="left",
|
|
969
|
+
box=rich.box.ROUNDED,
|
|
970
|
+
)
|
|
971
|
+
table.add_column("Parameter", style="cyan", no_wrap=True)
|
|
972
|
+
table.add_column("Value", style="orange1")
|
|
973
|
+
table.add_row("Start phase", str(tr.high_phase))
|
|
974
|
+
table.add_row("End phase", str(tr.low_phase))
|
|
975
|
+
table.add_row("Tcrit / GeV", str(tr.Tcrit * self.pot.conversionFactor))
|
|
976
|
+
console.print(table)
|