-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathyukawa.py
229 lines (183 loc) · 6.48 KB
/
yukawa.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
"""
A simple example model, of a real scalar field coupled to a Dirac fermion
c.f. 2310.02308
"""
import pathlib
import numpy as np
# WallGo imports
import WallGo
from WallGo import Fields, GenericModel, Particle
class YukawaModel(GenericModel):
"""
The Yukawa model, inheriting from WallGo.GenericModel.
"""
def __init__(self) -> None:
"""
Initialize the Yukawa model.
"""
self.modelParameters: dict[str, float] = {}
# Initialize internal effective potential
self.effectivePotential = EffectivePotentialYukawa(self)
# Create a list of particles relevant for the Boltzmann equations
self.defineParticles()
# ~ GenericModel interface
@property
def fieldCount(self) -> int:
"""How many classical background fields"""
return 1
def getEffectivePotential(self) -> "EffectivePotentialYukawa":
return self.effectivePotential
# ~
def defineParticles(self) -> None:
"""
Define the out-of-equilibrium particles for the model.
"""
self.clearParticles()
# === left fermion ===
# Vacuum mass squared
def psiMsqVacuum(fields: Fields) -> Fields:
return (
self.modelParameters["mf"]
+ self.modelParameters["y"] * fields.getField(0)
) ** 2
# Field-derivative of the vacuum mass squared
def psiMsqDerivative(fields: Fields) -> Fields:
return (
2
* self.modelParameters["y"]
* (
self.modelParameters["mf"]
+ self.modelParameters["y"] * fields.getField(0)
)
)
# Thermal mass
def psiMsqThermal(T: float) -> float:
return 1 / 16 * self.modelParameters["y"] ** 2 * T**2
psiL = Particle(
"psiL",
index=1,
msqVacuum=psiMsqVacuum,
msqDerivative=psiMsqDerivative,
msqThermal=psiMsqThermal,
statistics="Fermion",
totalDOFs=2,
)
psiR = Particle(
"psiR",
index=2,
msqVacuum=psiMsqVacuum,
msqDerivative=psiMsqDerivative,
msqThermal=psiMsqThermal,
statistics="Fermion",
totalDOFs=2,
)
self.addParticle(psiL)
self.addParticle(psiR)
class EffectivePotentialYukawa(WallGo.EffectivePotential):
"""
Effective potential for the Yukawa model.
"""
def __init__(self, owningModel: YukawaModel) -> None:
"""
Initialize the EffectivePotentialYukawa.
"""
super().__init__()
assert owningModel is not None, "Invalid model passed to Veff"
self.owner = owningModel
self.modelParameters = self.owner.modelParameters
# ~ EffectivePotential interface
fieldCount = 1
"""How many classical background fields"""
effectivePotentialError = 1e-15
"""
Relative accuracy at which the potential can be computed. Here the potential is
polynomial so we can set it to the machine precision.
"""
# ~
def evaluate(self, fields: Fields, temperature: float) -> float | np.ndarray:
"""
Evaluate the effective potential.
"""
# getting the field from the list of fields (here just of length 1)
fields = WallGo.Fields(fields)
phi = fields.getField(0)
# the constant term
f0 = -np.pi**2 / 90 * (1 + 4 * 7 / 8) * temperature**4
# coefficients of the temperature and field dependent terms
y = self.modelParameters["y"]
mf = self.modelParameters["mf"]
sigmaEff = (
self.modelParameters["sigma"]
+ 1 / 24 * (self.modelParameters["gamma"] + 4 * y * mf) * temperature**2
)
msqEff = (
self.modelParameters["msq"]
+ 1 / 24 * (self.modelParameters["lam"] + 4 * y**2) * temperature**2
)
potentialTotal = (
f0
+ sigmaEff * phi
+ 1 / 2 * msqEff * phi**2
+ 1 / 6 * self.modelParameters["gamma"] * phi**3
+ 1 / 24 * self.modelParameters["lam"] * phi**4
)
return np.array(potentialTotal)
def main() -> None:
manager = WallGo.WallGoManager()
# Change the amount of grid points in the spatial coordinates
# for faster computations
manager.config.configGrid.spatialGridSize = 20
# Increase the number of iterations in the wall solving to
# ensure convergence
manager.config.configEOM.maxIterations = 25
# Decrease error tolerance for phase tracing to ensure stability
manager.config.configThermodynamics.phaseTracerTol = 1e-8
pathtoCollisions = pathlib.Path(__file__).resolve().parent / pathlib.Path(
f"CollisionOutput_N11"
)
manager.setPathToCollisionData(pathtoCollisions)
model = YukawaModel()
manager.registerModel(model)
inputParameters = {
"sigma": 0.0,
"msq": 1.0,
"gamma": -1.2,
"lam": 0.10,
"y": 0.55,
"mf": 0.30,
}
model.modelParameters.update(inputParameters)
manager.setupThermodynamicsHydrodynamics(
WallGo.PhaseInfo(
temperature=8.0, # nucleation temperature
phaseLocation1=WallGo.Fields([0.4]),
phaseLocation2=WallGo.Fields([27.0]),
),
WallGo.VeffDerivativeSettings(
temperatureVariationScale=1.0,
fieldValueVariationScale=[100.0],
),
)
# ---- Solve wall speed in Local Thermal Equilibrium (LTE) approximation
vwLTE = manager.wallSpeedLTE()
print(f"LTE wall speed: {vwLTE:.6f}")
solverSettings = WallGo.WallSolverSettings(
bIncludeOffEquilibrium=False,
# meanFreePathScale is determined here by the annihilation channels,
# and scales inversely with y^4 or lam^2. This is why
# meanFreePathScale has to be so large.
meanFreePathScale=10000.0, # In units of 1/Tnucl
wallThicknessGuess=10.0, # In units of 1/Tnucl
)
results = manager.solveWall(solverSettings)
print(
f"Wall velocity without out-of-equilibrium contributions {results.wallVelocity:.6f}"
)
solverSettings.bIncludeOffEquilibrium = True
results = manager.solveWall(solverSettings)
print(
f"Wall velocity with out-of-equilibrium contributions {results.wallVelocity:.6f}"
)
## Don't run the main function if imported to another file
if __name__ == "__main__":
main()