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,647 @@
|
|
|
1
|
+
"""This module contains routines to compute the hydrodynamics
|
|
2
|
+
of the expanding bubbles.
|
|
3
|
+
|
|
4
|
+
Based on the code snippet provided in `arxiv:2303.10171`.
|
|
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.integrate import solve_ivp, simpson
|
|
16
|
+
from scipy.optimize import root_scalar
|
|
17
|
+
|
|
18
|
+
from transitionlistener import generic_potential
|
|
19
|
+
from transitionlistener.phases import PhaseInfo
|
|
20
|
+
|
|
21
|
+
from . import console
|
|
22
|
+
from rich import print
|
|
23
|
+
from rich.panel import Panel
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _local_temperature_step(pot, T: float) -> float:
|
|
27
|
+
"""Finite-difference temperature step that keeps the stencil at T > 0."""
|
|
28
|
+
T_abs = abs(float(T))
|
|
29
|
+
dT = max(float(getattr(pot, "T_eps", 1e-3)), T_abs * 1.0e-4)
|
|
30
|
+
if T_abs > 0.0:
|
|
31
|
+
dT = min(dT, 0.25 * T_abs)
|
|
32
|
+
return dT
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def kappa_sw(alpha : float, vw: float, cs: float) -> float:
|
|
36
|
+
"""Approximate the sound-wave efficiency factor using fit formulas from
|
|
37
|
+
1004.4187 by Jose R. Espinosa, Thomas Konstandin, Jose M. No &
|
|
38
|
+
Geraldine Servant
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
alpha : float
|
|
43
|
+
The strength of the phase transition at nucleation.
|
|
44
|
+
vw : float
|
|
45
|
+
The bubble wall velocity.
|
|
46
|
+
cs : float
|
|
47
|
+
The speed of sound in the broken phase.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
float
|
|
52
|
+
The sound-wave efficiency factor.
|
|
53
|
+
"""
|
|
54
|
+
# Intermediate kappas, Jouguet velocity
|
|
55
|
+
kA = vw**(6/5) * 6.9 * alpha / (1.36 - 0.037 * np.sqrt(alpha) + alpha)
|
|
56
|
+
kB = alpha**(2/5) / (0.017 + (0.997 + alpha)**(2/5))
|
|
57
|
+
kC = np.sqrt(alpha) / (0.135 + np.sqrt(0.98 + alpha))
|
|
58
|
+
kD = alpha / (0.73 + 0.083 * np.sqrt(alpha) + alpha)
|
|
59
|
+
dK = -0.9 * np.log(np.sqrt(alpha) / (1 + np.sqrt(alpha)))
|
|
60
|
+
vJ = (cs + np.sqrt(alpha**2 + 2 * alpha / 3)) / (1 + alpha)
|
|
61
|
+
lK = kC - kB - (vJ - cs) * dK
|
|
62
|
+
|
|
63
|
+
if vw <= cs: # Choose regime
|
|
64
|
+
num = (cs**(11/5) * kA * kB)
|
|
65
|
+
denom = ((cs**(11/5) - vw**(11/5)) * kB + vw * cs**(6/5) * kA)
|
|
66
|
+
return num / denom
|
|
67
|
+
elif vw < vJ:
|
|
68
|
+
return kB + (vw - cs) * dK + ((vw - cs)**3 / (vJ - cs)**3) * lK
|
|
69
|
+
else:
|
|
70
|
+
num = (vJ - 1)**3 * vJ**(5/2) * vw**(-5/2) * kC * kD
|
|
71
|
+
denom = ((vJ - 1)**3 - (vw - 1)**3) * vJ**(5/2) * kC + (vw - 1)**3 * kD
|
|
72
|
+
return num / denom
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class Hydrodynamics():
|
|
76
|
+
"""Provide hydrodynamic solutions for expanding first-order phase transition bubbles."""
|
|
77
|
+
|
|
78
|
+
def __init__(self, pot : generic_potential, high_phase : PhaseInfo,
|
|
79
|
+
low_phase : PhaseInfo, verbose=False):
|
|
80
|
+
"""Store the potential and phase data used to solve the hydrodynamics problem.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
pot : generic_potential
|
|
85
|
+
The effective potential describing the plasma.
|
|
86
|
+
high_phase : PhaseInfo
|
|
87
|
+
Phase outside the bubble wall.
|
|
88
|
+
low_phase : PhaseInfo
|
|
89
|
+
Phase inside the bubble wall.
|
|
90
|
+
verbose : bool, optional
|
|
91
|
+
Toggle diagnostic logging for root finding and integration steps.
|
|
92
|
+
"""
|
|
93
|
+
self.pot = pot
|
|
94
|
+
self.high_phase = high_phase
|
|
95
|
+
self.low_phase = low_phase
|
|
96
|
+
self.verbose = verbose
|
|
97
|
+
|
|
98
|
+
def calc_cs(self, T: float, sym: bool) -> float:
|
|
99
|
+
"""Calculate the speed of sound in the broken phase.
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
T : float
|
|
104
|
+
Temperature, typically at nucleation
|
|
105
|
+
sym : bool
|
|
106
|
+
Whether to use symmetric or broken phase
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
----------
|
|
110
|
+
float
|
|
111
|
+
speed of sound in the broken phase.
|
|
112
|
+
"""
|
|
113
|
+
phase = self.high_phase if sym else self.low_phase
|
|
114
|
+
dT = _local_temperature_step(self.pot, T)
|
|
115
|
+
phi = phase.valAt(T)
|
|
116
|
+
dVdT = self.pot.dVdT(phi, T, dT=dT, include_decoupled=False)
|
|
117
|
+
ddVdT = self.pot.d2VdT2(phi, T, dT=dT, include_decoupled=False)
|
|
118
|
+
cs = np.sqrt(dVdT/(T*ddVdT))
|
|
119
|
+
return cs
|
|
120
|
+
|
|
121
|
+
def calcWallVelocityLTE(self, Tn: float) -> float:
|
|
122
|
+
"""Calculate the wall velocity in local thermal equilibrium (LTE).
|
|
123
|
+
This is done by solving the matching conditions across the bubble wall.
|
|
124
|
+
It is based on the method described in `arxiv:2303.10171`.
|
|
125
|
+
|
|
126
|
+
Whether the species directly coupled to the scalar undergoing the
|
|
127
|
+
phase transition and the rest of the heat bath behave as a single
|
|
128
|
+
fluid or as two fluids is read from
|
|
129
|
+
``pot.config.gwConf.coupled_hydrodynamics``. The bubble wall always
|
|
130
|
+
does work on the species coupled to the transitioning scalar; the
|
|
131
|
+
rest of the heat bath is only directly coupled to the wall when this
|
|
132
|
+
flag is ``True``. (When it is ``False``, the two sectors can still be
|
|
133
|
+
in thermal contact through indirect, slower processes; this switch
|
|
134
|
+
only controls whether they are treated as a single hydrodynamic
|
|
135
|
+
fluid in the matching conditions.)
|
|
136
|
+
|
|
137
|
+
Parameters
|
|
138
|
+
----------
|
|
139
|
+
Tn : float
|
|
140
|
+
Temperature, typically at nucleation
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
----------
|
|
144
|
+
float
|
|
145
|
+
wall velocity in local thermal equilibrium.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
coupled = bool(self.pot.config.gwConf.coupled_hydrodynamics)
|
|
149
|
+
dT = _local_temperature_step(self.pot, Tn)
|
|
150
|
+
phi_s = self.high_phase.valAt(Tn)
|
|
151
|
+
phi_b = self.low_phase.valAt(Tn)
|
|
152
|
+
dVdT_s = self.pot.dVdT(phi_s, Tn, dT=dT, include_decoupled=coupled)
|
|
153
|
+
dVdT_b = self.pot.dVdT(phi_b, Tn, dT=dT, include_decoupled=coupled)
|
|
154
|
+
ddVdT_s = self.pot.d2VdT2(phi_s, Tn, dT=dT, include_decoupled=coupled)
|
|
155
|
+
ddVdT_b = self.pot.d2VdT2(phi_b, Tn, dT=dT, include_decoupled=coupled)
|
|
156
|
+
|
|
157
|
+
w_s = - Tn * dVdT_s
|
|
158
|
+
w_b = - Tn * dVdT_b
|
|
159
|
+
psi_n = w_b/w_s
|
|
160
|
+
cs2 = dVdT_s/(Tn*ddVdT_s)
|
|
161
|
+
cb2 = dVdT_b/(Tn*ddVdT_b)
|
|
162
|
+
|
|
163
|
+
# Calculate the alpha definition from the paper
|
|
164
|
+
# eq. (19) in `arxiv:2303.10171`
|
|
165
|
+
p_s = - self.pot.Vtot(phi_s, Tn, include_decoupled=coupled)
|
|
166
|
+
p_b = - self.pot.Vtot(phi_b, Tn, include_decoupled=coupled)
|
|
167
|
+
|
|
168
|
+
e_s = w_s - p_s
|
|
169
|
+
e_b = w_b - p_b
|
|
170
|
+
|
|
171
|
+
DTheta = (e_s - p_s/cb2 - (e_b - p_b/cb2))
|
|
172
|
+
alpha = DTheta / (3*w_s)
|
|
173
|
+
|
|
174
|
+
vw = self.find_vw(alpha, cb2, cs2, psi_n)
|
|
175
|
+
return vw
|
|
176
|
+
|
|
177
|
+
def find_vJ(self, alN: float, cb2: float) -> float:
|
|
178
|
+
"""Calculate the Jouguet velocity, i.e. the smallest wall velocity a
|
|
179
|
+
physically consistent detonation solution is allowed to have from the
|
|
180
|
+
PT strength α and sound speed.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
alN : float
|
|
185
|
+
Strength of the phase transition at nucleation.
|
|
186
|
+
cb2 : float
|
|
187
|
+
Sound speed squared in the broken phase.
|
|
188
|
+
|
|
189
|
+
Returns
|
|
190
|
+
-------
|
|
191
|
+
float
|
|
192
|
+
The Jouguet velocity.
|
|
193
|
+
"""
|
|
194
|
+
return np.sqrt(cb2) * (1 + np.sqrt(3 * alN * (1 - cb2 + 3 * cb2 * alN))) \
|
|
195
|
+
/ (1 + 3 * cb2 * alN)
|
|
196
|
+
|
|
197
|
+
def get_vp(self, vm: float, al: float, cb2: float, branch=-1) -> float:
|
|
198
|
+
"""Find the veloity outside the bubble using the
|
|
199
|
+
matching conditions.
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
vm : float
|
|
204
|
+
The plasma velocity in the wall frame inside the bubble.
|
|
205
|
+
al : float
|
|
206
|
+
Strength of the phase transition at nucleation.
|
|
207
|
+
cb2 : float
|
|
208
|
+
The speed of sound squared in the broken phase.
|
|
209
|
+
branch : int
|
|
210
|
+
Choose the branch of the solution, either -1 or +1.
|
|
211
|
+
Returns
|
|
212
|
+
-------
|
|
213
|
+
float
|
|
214
|
+
The plasma velocity in the wall frame outside the bubble.
|
|
215
|
+
"""
|
|
216
|
+
disc = vm**4 - 2*cb2 * vm**2*(1 - 6*al) + cb2**2*(1 - 12*vm**2 * al * (1 - 3*al))
|
|
217
|
+
return 0.5 * (cb2 + vm**2 + branch * np.sqrt(disc))/(vm + 3*cb2 * vm * al)
|
|
218
|
+
|
|
219
|
+
def w_from_alpha(self, al: float, alN: float, nu: float, mu: float) -> float:
|
|
220
|
+
"""Compute the enthalpy from alpha
|
|
221
|
+
|
|
222
|
+
Parameters
|
|
223
|
+
----------
|
|
224
|
+
al : float
|
|
225
|
+
Strength of the phase transition at the wall.
|
|
226
|
+
alN : float
|
|
227
|
+
Strength of the phase transition at nucleation.
|
|
228
|
+
nu : float
|
|
229
|
+
Parameter depending on the speed of sound in the broken phase.
|
|
230
|
+
mu : float
|
|
231
|
+
Parameter depending on the speed of sound in the symmetric phase.
|
|
232
|
+
|
|
233
|
+
Returns
|
|
234
|
+
-------
|
|
235
|
+
float
|
|
236
|
+
The enthalpy in the wall frame.
|
|
237
|
+
"""
|
|
238
|
+
return (abs((1 - 3 * alN) * mu - nu) +1e-100) / (abs ((1 -3* al) * mu - nu) +1e-100)
|
|
239
|
+
|
|
240
|
+
def eqWall(self, al : float, alN: float, vm: float, nu: float,
|
|
241
|
+
mu: float, psiN: float, solution: int = -1):
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
Parameters
|
|
245
|
+
----------
|
|
246
|
+
al : float
|
|
247
|
+
Strength of the phase transition at the wall.
|
|
248
|
+
alN : float
|
|
249
|
+
Strength of the phase transition at nucleation.
|
|
250
|
+
vm : float
|
|
251
|
+
Velocity of the fluid at the wall.
|
|
252
|
+
nu : float
|
|
253
|
+
Parameter depending on the speed of sound in the broken phase.
|
|
254
|
+
mu : float
|
|
255
|
+
Parameter depending on the speed of sound in the symmetric phase.
|
|
256
|
+
psiN : float
|
|
257
|
+
Ratio of enthalpies at nucleation.
|
|
258
|
+
solution : int
|
|
259
|
+
Choose the branch of the solution, either -1 or +1.
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
float
|
|
264
|
+
The value of the matching condition equation.
|
|
265
|
+
|
|
266
|
+
"""
|
|
267
|
+
vp = self.get_vp(vm, al ,1/(nu -1), solution)
|
|
268
|
+
ga2m, ga2p = 1/(1 - vm**2) ,1/(1 - vp**2)
|
|
269
|
+
psi = psiN * self.w_from_alpha(al, alN, nu, mu)**(nu / mu -1)
|
|
270
|
+
return vp * vm * al /(1 -(nu -1) * vp * vm) -(1 -3* al -(ga2p / ga2m)**(nu /2) *
|
|
271
|
+
psi) /(3* nu)
|
|
272
|
+
|
|
273
|
+
def solve_alpha(self, vw, alN, cb2, cs2, psiN):
|
|
274
|
+
"""Find the strength of the phase transition at the wall.
|
|
275
|
+
|
|
276
|
+
Parameters
|
|
277
|
+
----------
|
|
278
|
+
vw : float
|
|
279
|
+
Velocity of the fluid at the wall.
|
|
280
|
+
alN : float
|
|
281
|
+
Strength of the phase transition at nucleation.
|
|
282
|
+
cb2 : float
|
|
283
|
+
Speed of sound squared in the broken phase.
|
|
284
|
+
cs2 : float
|
|
285
|
+
Speed of sound squared in the symmetric phase.
|
|
286
|
+
psiN : float
|
|
287
|
+
Ratio of enthalpies at nucleation.
|
|
288
|
+
|
|
289
|
+
Returns
|
|
290
|
+
-------
|
|
291
|
+
float
|
|
292
|
+
The strength of the phase transition at the wall.
|
|
293
|
+
"""
|
|
294
|
+
nu, mu = 1+1/ cb2 ,1+1/ cs2
|
|
295
|
+
vm = min(np.sqrt(cb2), vw)
|
|
296
|
+
vp_max = min(cs2 / vw, vw)
|
|
297
|
+
al_min = max ((vm - vp_max) *(cb2 - vm * vp_max) /(3* cb2 * vm *(1 - vp_max**2)),
|
|
298
|
+
(mu - nu) /(3* mu))
|
|
299
|
+
al_max = 1/3
|
|
300
|
+
branch = -1
|
|
301
|
+
if self.eqWall(al_min, alN, vm, nu, mu, psiN) * \
|
|
302
|
+
self.eqWall(al_max, alN, vm, nu, mu, psiN) > 0:
|
|
303
|
+
branch = 1
|
|
304
|
+
|
|
305
|
+
sol = root_scalar(self.eqWall, (alN, vm, nu, mu, psiN, branch),
|
|
306
|
+
bracket=(al_min, al_max), rtol=1e-10, xtol=1e-10)
|
|
307
|
+
|
|
308
|
+
if not sol.converged and self.verbose:
|
|
309
|
+
print("WARNING: desired precision not reached in 'solve_alpha'")
|
|
310
|
+
return sol.root
|
|
311
|
+
|
|
312
|
+
def dfdv(self, v : float, X : np.ndarray, cs2 : float) -> list[float]:
|
|
313
|
+
"""
|
|
314
|
+
Compute the derivatives for the hydrodynamic equations.
|
|
315
|
+
|
|
316
|
+
Parameters
|
|
317
|
+
----------
|
|
318
|
+
v : float
|
|
319
|
+
Velocity of the fluid.
|
|
320
|
+
X : np.ndarray
|
|
321
|
+
Array containing the variables [xi, w].
|
|
322
|
+
cs2 : float
|
|
323
|
+
Speed of sound squared.
|
|
324
|
+
|
|
325
|
+
Returns
|
|
326
|
+
-------
|
|
327
|
+
list[float]
|
|
328
|
+
The derivatives [dXidv, dwdv].
|
|
329
|
+
"""
|
|
330
|
+
xi, w = X
|
|
331
|
+
with np.errstate(divide='ignore', invalid='ignore'):
|
|
332
|
+
mu_xiv = (xi - v) / (1 - xi * v)
|
|
333
|
+
dxidv = xi * (1 - v * xi) * (mu_xiv**2 / cs2 - 1) / (2 * v * (1 - v**2))
|
|
334
|
+
dwdv = w * (1 + 1 / cs2) * mu_xiv / (1 - v**2)
|
|
335
|
+
return [dxidv, dwdv]
|
|
336
|
+
|
|
337
|
+
def integrate_plasma(self, v0, vw, w0, c2, shock_wave=True):
|
|
338
|
+
"""
|
|
339
|
+
Integrate the hydrodynamic equations for the plasma profile.
|
|
340
|
+
|
|
341
|
+
Parameters
|
|
342
|
+
----------
|
|
343
|
+
v0 : float
|
|
344
|
+
Initial velocity of the fluid.
|
|
345
|
+
vw : float
|
|
346
|
+
Velocity of the fluid at the wall.
|
|
347
|
+
w0 : float
|
|
348
|
+
Initial value of w.
|
|
349
|
+
c2 : float
|
|
350
|
+
Speed of sound squared.
|
|
351
|
+
shock_wave : bool
|
|
352
|
+
Whether to include shock wave effects.
|
|
353
|
+
|
|
354
|
+
Returns
|
|
355
|
+
----------
|
|
356
|
+
OdeResult
|
|
357
|
+
The result of the integration containing the plasma profile.
|
|
358
|
+
"""
|
|
359
|
+
def event (v ,X, cs2):
|
|
360
|
+
xi, w = X
|
|
361
|
+
return xi*(xi - v) / (1 - xi*v) - cs2
|
|
362
|
+
|
|
363
|
+
event.terminal = True
|
|
364
|
+
sol = None
|
|
365
|
+
if shock_wave :
|
|
366
|
+
sol = solve_ivp(self.dfdv, (v0 ,1e-20), [ vw, w0] ,
|
|
367
|
+
events= event, args=(c2,), rtol=1e-10, atol=1e-10)
|
|
368
|
+
else:
|
|
369
|
+
sol = solve_ivp(self.dfdv,(v0 ,1e-20), [vw, w0] ,
|
|
370
|
+
args=(c2,), rtol=1e-10, atol=1e-10)
|
|
371
|
+
if not sol.success and self.verbose:
|
|
372
|
+
print(" WARNING : desired precision not reached in 'integrate_plasma'")
|
|
373
|
+
|
|
374
|
+
return sol
|
|
375
|
+
|
|
376
|
+
def shooting(self, vw : float, alN : float, cb2 : float, cs2 : float, psiN : float) -> float:
|
|
377
|
+
""" Shooting method to find the wall velocity consistent with matching conditions.
|
|
378
|
+
|
|
379
|
+
Parameters
|
|
380
|
+
----------
|
|
381
|
+
vw : float
|
|
382
|
+
Velocity of the fluid at the wall.
|
|
383
|
+
alN : float
|
|
384
|
+
Strength of the phase transition at nucleation.
|
|
385
|
+
cb2 : float
|
|
386
|
+
Speed of sound squared in the broken phase.
|
|
387
|
+
cs2 : float
|
|
388
|
+
Speed of sound squared in the symmetric phase.
|
|
389
|
+
psiN : float
|
|
390
|
+
Ratio of enthalpies at nucleation.
|
|
391
|
+
|
|
392
|
+
Returns
|
|
393
|
+
-------
|
|
394
|
+
float
|
|
395
|
+
The value of the shooting function.
|
|
396
|
+
"""
|
|
397
|
+
nu, mu = 1+1/cb2 ,1+1/ cs2
|
|
398
|
+
vm = min(np.sqrt(cb2), vw)
|
|
399
|
+
al = self.solve_alpha(vw, alN, cb2, cs2, psiN)
|
|
400
|
+
vp = self.get_vp(vm, al, cb2)
|
|
401
|
+
wp = self.w_from_alpha(al, alN, nu, mu)
|
|
402
|
+
sol = self.integrate_plasma ((vw - vp) /(1 - vw * vp), vw, wp, cs2)
|
|
403
|
+
vp_sw = sol.y[0, -1]
|
|
404
|
+
vm_sw = (vp_sw - sol.t[-1]) /(1 - vp_sw * sol.t[-1])
|
|
405
|
+
wm_sw = sol.y[1, -1]
|
|
406
|
+
return vp_sw / vm_sw - ((mu -1) * wm_sw +1) /((mu -1) + wm_sw)
|
|
407
|
+
|
|
408
|
+
def max_al(self, cb2 : float, cs2 : float, psiN : float,
|
|
409
|
+
upper_limit : float =1) -> float:
|
|
410
|
+
"""Return the maximal nucleation-strength compatible with
|
|
411
|
+
subsonic solutions.
|
|
412
|
+
|
|
413
|
+
Parameters
|
|
414
|
+
----------
|
|
415
|
+
cb2 : float
|
|
416
|
+
Speed of sound squared in the broken phase.
|
|
417
|
+
cs2 : float
|
|
418
|
+
Speed of sound squared in the symmetric phase.
|
|
419
|
+
psiN : float
|
|
420
|
+
Ratio of enthalpies at nucleation.
|
|
421
|
+
upper_limit : float
|
|
422
|
+
Upper limit for the search of maximal alpha.
|
|
423
|
+
|
|
424
|
+
Returns
|
|
425
|
+
-------
|
|
426
|
+
float
|
|
427
|
+
The maximal nucleation-strength compatible with subsonic solutions.
|
|
428
|
+
|
|
429
|
+
"""
|
|
430
|
+
nu, mu = 1+1/ cb2 ,1+1/ cs2
|
|
431
|
+
vm = np.sqrt(cb2)
|
|
432
|
+
|
|
433
|
+
def func(alN):
|
|
434
|
+
vw = self.find_vJ(alN, cb2)
|
|
435
|
+
vp = cs2 / vw
|
|
436
|
+
ga2p, ga2m = 1/(1 - vp**2) ,1/(1 - vm**2)
|
|
437
|
+
wp = (vp + vw - vw * mu) /(vp + vw - vp * mu)
|
|
438
|
+
psi = psiN * wp**(nu / mu -1)
|
|
439
|
+
al = (mu - nu) /(3* mu) +(alN -(mu - nu) /(3* mu)) / wp
|
|
440
|
+
return vp * vm * al /(1 -(nu -1) * vp * vm) -(
|
|
441
|
+
1 -3* al -(ga2p / ga2m)**(nu /2) * psi) /(3*nu)
|
|
442
|
+
|
|
443
|
+
if func(upper_limit) < 0:
|
|
444
|
+
return upper_limit
|
|
445
|
+
sol = root_scalar(func, bracket =((1 - psiN) /3, upper_limit),
|
|
446
|
+
rtol =1e-10, xtol =1e-10)
|
|
447
|
+
return sol.root
|
|
448
|
+
|
|
449
|
+
def find_vw(self, alN : float, cb2 : float, cs2 : float,
|
|
450
|
+
psiN : float) -> float:
|
|
451
|
+
"""Solve for the wall velocity consistent with matching conditions.
|
|
452
|
+
|
|
453
|
+
Parameters
|
|
454
|
+
----------
|
|
455
|
+
alN : float
|
|
456
|
+
Strength of the phase transition at nucleation.
|
|
457
|
+
cb2 : float
|
|
458
|
+
Speed of sound squared in the broken phase.
|
|
459
|
+
cs2 : float
|
|
460
|
+
Speed of sound squared in the symmetric phase.
|
|
461
|
+
psiN : float
|
|
462
|
+
Ratio of enthalpies at nucleation.
|
|
463
|
+
|
|
464
|
+
Returns
|
|
465
|
+
-------
|
|
466
|
+
float
|
|
467
|
+
The wall velocity consistent with matching conditions.
|
|
468
|
+
|
|
469
|
+
"""
|
|
470
|
+
nu, mu = 1+1/ cb2 ,1+1/ cs2
|
|
471
|
+
vJ = self.find_vJ(alN, cb2)
|
|
472
|
+
if alN < (1 - psiN) /3 or alN <=(mu - nu) /(3* mu):
|
|
473
|
+
if self.verbose:
|
|
474
|
+
print("alpha_N is too small to find a solution for the wall velocity, set it to 0.")
|
|
475
|
+
return 0
|
|
476
|
+
if alN > self.max_al(cb2, cs2, psiN ,100) or self.shooting(vJ, alN, cb2, cs2, psiN) < 0:
|
|
477
|
+
if self.verbose:
|
|
478
|
+
print("alpha_N too large to find a solution for the wall velocity, set it to 1.")
|
|
479
|
+
return 1
|
|
480
|
+
sol = root_scalar(self.shooting, (alN, cb2, cs2, psiN) ,
|
|
481
|
+
bracket =[1e-3, vJ], rtol =1e-10, xtol =1e-10)
|
|
482
|
+
return sol.root
|
|
483
|
+
|
|
484
|
+
def detonation(self, alN : float, cb2 : float, psiN : float) -> float:
|
|
485
|
+
"""Return the detonation wall velocity if a solution exists.
|
|
486
|
+
|
|
487
|
+
Parameters
|
|
488
|
+
----------
|
|
489
|
+
alN : float
|
|
490
|
+
Strength of the phase transition at nucleation.
|
|
491
|
+
cb2 : float
|
|
492
|
+
Speed of sound squared in the broken phase.
|
|
493
|
+
psiN : float
|
|
494
|
+
Ratio of enthalpies at nucleation.
|
|
495
|
+
|
|
496
|
+
Returns
|
|
497
|
+
-------
|
|
498
|
+
float
|
|
499
|
+
The detonation wall velocity if a solution exists, otherwise 0.
|
|
500
|
+
"""
|
|
501
|
+
nu = 1+1/cb2
|
|
502
|
+
vJ = self.find_vJ(alN, cb2)
|
|
503
|
+
|
|
504
|
+
def matching_eq(vw):
|
|
505
|
+
A = vw**2+ cb2 *(1 -3* alN *(1 - vw**2))
|
|
506
|
+
vm =(A + np.sqrt(A**2 -4* vw**2* cb2)) /(2* vw)
|
|
507
|
+
ga2w, ga2m = 1/(1 - vw**2) ,1/(1 - vm**2)
|
|
508
|
+
return vw * vm * alN /(1 -(nu -1) * vw * vm) \
|
|
509
|
+
-(1 -3* alN -(ga2w / ga2m)**(nu /2) * psiN)/(3* nu)
|
|
510
|
+
|
|
511
|
+
if matching_eq(vJ +1e-10) * matching_eq (1 -1e-10) > 0:
|
|
512
|
+
if self.verbose:
|
|
513
|
+
print('No detonation solution')
|
|
514
|
+
return 0
|
|
515
|
+
|
|
516
|
+
sol = root_scalar(matching_eq, bracket =(vJ +1e-10 ,1 -1e-10),
|
|
517
|
+
rtol =1e-10, xtol =1e-10)
|
|
518
|
+
return sol.root
|
|
519
|
+
|
|
520
|
+
def find_kappa(self, alN : float, cb2 : float, cs2 : float,
|
|
521
|
+
psiN : float, vw : float = None) -> float:
|
|
522
|
+
"""Compute the hydrodynamic efficiency factor for given plasma parameters.
|
|
523
|
+
|
|
524
|
+
Parameters
|
|
525
|
+
----------
|
|
526
|
+
alN : float
|
|
527
|
+
Strength of the phase transition at nucleation.
|
|
528
|
+
cb2 : float
|
|
529
|
+
Speed of sound squared in the broken phase.
|
|
530
|
+
cs2 : float
|
|
531
|
+
Speed of sound squared in the symmetric phase.
|
|
532
|
+
psiN : float
|
|
533
|
+
Ratio of enthalpies at nucleation.
|
|
534
|
+
vw : float, optional
|
|
535
|
+
Wall velocity. If not provided, it will be computed.
|
|
536
|
+
|
|
537
|
+
Returns
|
|
538
|
+
-------
|
|
539
|
+
float
|
|
540
|
+
The hydrodynamic efficiency factor.
|
|
541
|
+
"""
|
|
542
|
+
if vw is None:
|
|
543
|
+
vw = self.find_vw(alN, cb2, cs2, psiN)
|
|
544
|
+
nu, mu = 1 + 1/cb2, 1 + 1/cs2
|
|
545
|
+
kappa, wp, vm, vp = 0, 1 ,0 ,0
|
|
546
|
+
if vw < 1:
|
|
547
|
+
vm = min(np.sqrt(cb2), vw)
|
|
548
|
+
al = self.solve_alpha(vw, alN, cb2, cs2, psiN)
|
|
549
|
+
vp = self.get_vp(vm, al, cb2)
|
|
550
|
+
wp = self.w_from_alpha(al, alN, nu, mu)
|
|
551
|
+
sol = self.integrate_plasma ((vw - vp) /(1 - vw * vp) ,vw, wp, cs2)
|
|
552
|
+
v, xi, w = sol.t, sol.y[0], sol.y [1]
|
|
553
|
+
kappa += 4 * simpson((xi * v)**2* w /(1 - v**2), xi) /(vw**3* alN)
|
|
554
|
+
if vw**2 > cb2:
|
|
555
|
+
w0 = psiN * wp**(nu / mu) * ((1 - vm**2)/(1 - vp**2))**(nu/2) \
|
|
556
|
+
if vw < 1 else 1+6*alN/(nu-2)
|
|
557
|
+
v0 = (vw - vm) / (1 - vw * vm) if vw < 1 else 3 * alN / (nu-2+3*alN)
|
|
558
|
+
sol = self.integrate_plasma(v0, vw, w0, cb2, False)
|
|
559
|
+
v, xi, w = np.flip(sol.t), np.flip(sol.y [0]), np.flip(sol.y [1])
|
|
560
|
+
mask = np.append(xi[1:] > xi [: -1], True)
|
|
561
|
+
kappa += 4 * simpson(((xi * v)**2* w /(1 - v**2))[mask], xi[mask]) \
|
|
562
|
+
/(vw**3* alN)
|
|
563
|
+
return kappa
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def calc_kappas(alphaN: float, alpha_inf: float, alpha_eq: float,
|
|
567
|
+
vw: float, cs: float, Rsep: float, R0: float, config) -> tuple:
|
|
568
|
+
"""
|
|
569
|
+
Calculate the kappa parameters kappa_phi, kappa_sw and kappa_turb.
|
|
570
|
+
These parameters quantify the amount of energy that is available
|
|
571
|
+
for gravitational wave production in the broken phase due to
|
|
572
|
+
bubble collisions, sound waves and turbulence.
|
|
573
|
+
|
|
574
|
+
Parameters
|
|
575
|
+
----------
|
|
576
|
+
alphaN : float
|
|
577
|
+
The strength of the phase transition at nucleation.
|
|
578
|
+
alpha_inf : float
|
|
579
|
+
The critical strength of the phase transition at which bubbles
|
|
580
|
+
would run away if there was only leading order friction.
|
|
581
|
+
alpha_eq : float
|
|
582
|
+
The critical strength of the phase transition at which
|
|
583
|
+
the next-to-leading order friction is compensated by a
|
|
584
|
+
high bubble wall velocity.
|
|
585
|
+
vw : float
|
|
586
|
+
The bubble wall velocity.
|
|
587
|
+
cs : float
|
|
588
|
+
The speed of sound in the broken phase.
|
|
589
|
+
Rsep : float
|
|
590
|
+
The mean bubble separation at the time of percolation.
|
|
591
|
+
R0 : float
|
|
592
|
+
The critical bubble radius at which the phase transition
|
|
593
|
+
starts at nucleation.
|
|
594
|
+
config : object
|
|
595
|
+
The configuration object containing for instance the
|
|
596
|
+
epsilon parameter determining the importance of
|
|
597
|
+
turbulence in the broken phase.
|
|
598
|
+
|
|
599
|
+
Returns
|
|
600
|
+
----------
|
|
601
|
+
kappa_bw : float
|
|
602
|
+
The kappa parameter for bubble wall collisions.
|
|
603
|
+
kappa_sw : float
|
|
604
|
+
The kappa parameter for sound waves.
|
|
605
|
+
kappa_turb : float
|
|
606
|
+
The kappa parameter for turbulence.
|
|
607
|
+
"""
|
|
608
|
+
# unknown parameter epsilon is to represent the fraction of overall kinetic energy
|
|
609
|
+
# in bulk motion that is converted to MHD turbulence, see arXiv:2403.03723 eq. (2.13)
|
|
610
|
+
eps = config.epsilon_turbulence
|
|
611
|
+
|
|
612
|
+
# Step 1:
|
|
613
|
+
# Computation of kappa_phi
|
|
614
|
+
# based on 1903.09642 by John Ellis, Marek
|
|
615
|
+
# Lewicki, José Miguel No & Ville Vaskonen
|
|
616
|
+
gamma_eq = np.inf if alpha_eq == 0 else (alphaN - alpha_inf) / alpha_eq
|
|
617
|
+
gamma_star = 2 * Rsep / (3 * R0)
|
|
618
|
+
|
|
619
|
+
def kappa_col(gamma_star, gamma_eq, alpha_inf, alpha):
|
|
620
|
+
if alpha < alpha_inf:
|
|
621
|
+
# If the leading-order friction is so large that the bubbles would not even reach
|
|
622
|
+
# relativistic terminal velocity, we set kappa_BW = 0.
|
|
623
|
+
return 0
|
|
624
|
+
if gamma_star > gamma_eq:
|
|
625
|
+
return (gamma_eq / gamma_star) * (1 - (alpha_inf / alpha) * (gamma_eq / gamma_star)**2)
|
|
626
|
+
else:
|
|
627
|
+
return 1 - alpha_inf / alpha
|
|
628
|
+
|
|
629
|
+
kappa_BW = 0
|
|
630
|
+
if config.bw_collisions == "off":
|
|
631
|
+
kappa_BW = 0
|
|
632
|
+
elif config.bw_collisions == "full":
|
|
633
|
+
kappa_BW = 1
|
|
634
|
+
elif config.bw_collisions == "NLO":
|
|
635
|
+
kappa_BW = kappa_col(gamma_star, gamma_eq, alpha_inf, alphaN)
|
|
636
|
+
else:
|
|
637
|
+
raise ValueError("Wrong config input: bw_collisions must be 'off', 'full' or 'NLO'.")
|
|
638
|
+
|
|
639
|
+
# Step 2:
|
|
640
|
+
# Computation of kappa_sw (assuming no kappa_phi)
|
|
641
|
+
# based on 1004.4187 by Jose R. Espinosa, Thomas Konstandin,
|
|
642
|
+
# Jose M. No & Geraldine Servant
|
|
643
|
+
|
|
644
|
+
alpha_eff = alphaN * (1 - kappa_BW)
|
|
645
|
+
kappa_SW = (1 - kappa_BW) * kappa_sw(alpha_eff, vw, cs)
|
|
646
|
+
kappa_TURB = eps * kappa_SW
|
|
647
|
+
return kappa_BW, kappa_SW, kappa_TURB
|