geff.models.fai_kh
$\newcommand{\bm}[1]{\boldsymbol{#1}}$ Defines the GEF model "fai_kh" corresponding to fermionic axion inflation with a heuristic scale dependence model through the instability scale $k_{\rm h}$.
For more details on this model, see e.g., 2408.16538.
The model knows the following variables:
- time variable:
t- cosmic time, $t$ - dynamical variables:
N- $e$-folds, $N$phi,dphi- inflaton amplitude, $\varphi$, and velocity, $\dot{\varphi}$kh- the instability scale, $k_{\rm h}$rhoChi- fermion energy density, $\rho_{\chi}$
- static variables:
a- scale factor, $a$H- Hubble rate, $H$ddphi- inflaton acceleration, $\ddot{\varphi}$E,B,G- gauge-field expectation values, $\langle \bm{E}^2 \rangle$, $\langle \bm{B}^2 \rangle$, -$\langle \bm{E} \cdot \bm{B} \rangle$xi- instability parameter, $\xi$sigmaE,sigmaB- electric and magnetic conductivities, $\sigma_{\rm E}$, $\sigma_{\rm B}$xieff- effective instability parameter, $\xi_{\rm eff}$kS- fermion momentum scale, $k_{\rm S}$
- constants:
beta- coupling strength, $\beta$
- functions:
V,dV- inflaton potential, $V(\varphi)$, and its derivative, $V_{,\varphi}(\varphi)$
- gauge field:
GF- tower of gauge bilinears, $\mathcal{F}_{\mathcal X}^{(n)}$
The model expects the following input:
phi,dphi- initial data on the inflaton, $\varphi$, $\dot\varphi$rhoChi- initial data on the fermion energy density, $\rho_{\chi}$beta- coupling strength, $\beta$V,dV- potential shape, $V(\varphi)$, $V_{,\varphi}(\varphi)$
The model tracks the following events:
- end of inflation - terminate solver when $\ddot{a} < 0$
- negative norms - return an error when $\langle \bm{E}^2 \rangle$ or $\langle \bm{B}^2 \rangle$ are negative
1r""" 2$\newcommand{\bm}[1]{\boldsymbol{#1}}$ 3Defines the GEF model "fai_kh" corresponding to fermionic axion inflation with a heuristic scale dependence model through the instability scale $k_{\rm h}$. 4 5For more details on this model, see e.g., [2408.16538](https://arxiv.org/abs/2408.16538). 6 7--- 8 9The model knows the following variables: 10* time variable: `t` - *cosmic time*, $t$ 11* dynamical variables: 12 * `N` - *$e$-folds*, $N$ 13 * `phi`, `dphi` - *inflaton amplitude, $\varphi$, and velocity, $\dot{\varphi}$* 14 * `kh` - *the instability scale, $k_{\rm h}$* 15 * `rhoChi` - *fermion energy density, $\rho_{\chi}$* 16* static variables: 17 * `a` - *scale factor, $a$* 18 * `H` - *Hubble rate, $H$* 19 * `ddphi` - *inflaton acceleration, $\ddot{\varphi}$* 20 * `E`, `B`, `G` - *gauge-field expectation values, $\langle \bm{E}^2 \rangle$, $\langle \bm{B}^2 \rangle$, -$\langle \bm{E} \cdot \bm{B} \rangle$* 21 * `xi` - *instability parameter, $\xi$* 22 * `sigmaE`, `sigmaB` - *electric and magnetic conductivities, $\sigma_{\rm E}$, $\sigma_{\rm B}$* 23 * `xieff` - *effective instability parameter, $\xi_{\rm eff}$* 24 * `kS` - *fermion momentum scale, $k_{\rm S}$* 25* constants: 26 * `beta` - *coupling strength, $\beta$* 27* functions: 28 * `V`,`dV` - *inflaton potential, $V(\varphi)$, and its derivative, $V_{,\varphi}(\varphi)$* 29* gauge field: 30 * `GF` - *tower of gauge bilinears, $\mathcal{F}_{\mathcal X}^{(n)}$* 31 32The model expects the following input: 33* `phi`, `dphi` - *initial data on the inflaton, $\varphi$, $\dot\varphi$* 34* `rhoChi` - *initial data on the fermion energy density, $\rho_{\chi}$* 35* `beta` - *coupling strength, $\beta$* 36* `V`, `dV` - *potential shape, $V(\varphi)$, $V_{,\varphi}(\varphi)$* 37 38The model tracks the following events: 39* end of inflation - terminate solver when $\ddot{a} < 0$ 40* negative norms - return an error when $\langle \bm{E}^2 \rangle$ or $\langle \bm{B}^2 \rangle$ are negative 41""" 42import numpy as np 43 44from geff.bgtypes import t, N, a, H, phi, dphi, ddphi, V, dV, E, B, G, xi, kh, beta, GF, define_var 45from geff.solver import TerminalEvent, ErrorEvent, GEFSolver 46from geff.mbm import ModeSolver 47 48from geff.utility.eom import (klein_gordon, friedmann, dlnkh, drhoChi, gauge_field_ode_schwinger, 49 conductivities_collinear, conductivities_mixed, check_accelerated_expansion) 50from geff.utility.boundary import boundary_pai 51from geff.utility.general import heaviside 52from geff.utility.mode import bd_classic, mode_equation_SE_scale 53from geff._docs import generate_docs, docs_models 54 55name = "FAI kh" 56"""The models name.""" 57 58settings = {"picture":"mixed"} 59"""The model settings. 60 61Possible settings are "mixed", "electric", "magnetic". 62 63Determines if conductivities are computed assuming collinear E&M fields 64("electric", "magnetic") or not ("mixed"). 65""" 66 67# parse settings 68def define_conductivity(): 69 if settings["picture"]=="mixed": 70 conductivity = conductivities_mixed 71 elif settings["picture"]=="electric": 72 def conductivity(a, H, E, B, G, omega): 73 return conductivities_collinear(a, H, E, B, G, -1, omega) 74 elif settings["picture"]=="magnetic": 75 def conductivity(a, H, E, B, G, omega): 76 return conductivities_collinear(a, H, E, B, G, 1, omega) 77 else: 78 raise KeyError(f"{settings['picture']} is an unknown choice for the setting'picture'") 79 return np.vectorize(conductivity) 80 81def interpret_settings(): 82 global conductivity 83 conductivity = define_conductivity() 84 return 85 86#Define additional variables 87sigmaE=define_var("sigmaE", 1, 0, "electric damping") 88sigmaB=define_var("sigmaB", 1, 0, "magnetic damping") 89xieff=define_var("xieff", 0, 0, "effective instability parameter") 90rhoChi=define_var("rhoChi", 4, 0, "fermion energy density") 91kS=define_var("kS", 1, 0, "fermion momentum scale")#Fermion energy density 92 93#Assign quantities to a dictionary, classifying them by their role: 94quantities={ 95 "time":[t], #time coordinate according to which EoMs are expressed 96 "dynamical":[N, phi, dphi, kh, rhoChi], #variables which evolve in time according to an EoM 97 "static":[a, H, xi, E, B, G, ddphi, sigmaE, sigmaB, xieff, kS], #variables which are derived from dynamical variables 98 "constant":[beta], #constant quantities in the model 99 "function":[V, dV], #functions of variables such as scalar potentials 100 "gauge":[GF] #Gauge fields whose dynamics is given in terms of bilinear towers of expectation values 101 } 102 103#State which variables require input for initialisation 104model_input = [phi, dphi, rhoChi, beta, V, dV] 105 106#this functions is called upon initialisation of the GEF class 107def define_units(phi, dphi, V, rhoChi): 108 #compute Hubble rate at t0 109 rhoK = 0.5*dphi**2 110 rhoV = V(phi) 111 H0 = friedmann( rhoK, rhoV, rhoChi ) 112 113 omega = H0 #Characteristic frequency is the initial Hubble rate 114 mu = 1. #Charatcterisic amplitude is the Planck mass 115 116 return omega, mu 117 118#the new function for sys_to_yini in GEFSolver 119def initial_conditions(sys, ntr): 120 yini = np.zeros((ntr+1)*3+5) 121 122 #from the 'input' dictionary 123 yini[0] = sys.N.value 124 yini[1] = sys.phi.value 125 yini[2] = sys.dphi.value 126 127 #needs to be computed 128 sys.initialise("kh")( abs(sys.dphi)*sys.beta ) 129 yini[3] = np.log(sys.kh.value) 130 131 #initialise rhoChi 132 yini[4] = sys.rhoChi.value 133 134 #all gauge-field expectation values are assumed to be 0 at initialisation 135 return yini 136 137#define update_sys for GEFSolver 138def update_values(t, y, sys, atol=1e-20, rtol=1e-6): 139 #spacetime variables 140 sys.t.value = t 141 sys.N.value = y[0] 142 sys.a.value = np.exp(y[0]) 143 144 #parse for convenience 145 sys.phi.value = y[1] 146 sys.dphi.value = y[2] 147 sys.kh.value = np.exp(y[3]) 148 149 sys.rhoChi.value = y[4] 150 151 #the gauge-field terms in y are not stored, save these values here 152 sys.E.value = y[5]*np.exp(4*(y[3]-y[0])) 153 sys.B.value = y[6]*np.exp(4*(y[3]-y[0])) 154 sys.G.value = y[7]*np.exp(4*(y[3]-y[0])) 155 156 #Hubble rate 157 sys.H.value = friedmann(0.5*sys.dphi**2, sys.V(sys.phi), 158 0.5*(sys.E+sys.B)*sys.omega**2, sys.rhoChi*sys.omega**2) 159 160 #conductivities 161 sigmaE, sigmaB, ks = conductivity(sys.a.value, sys.H.value, sys.E.value, 162 sys.B.value, sys.G.value, sys.omega) 163 sys.kS.value = ks 164 GlobalFerm = heaviside(np.log(ks), np.log(sys.a*sys.H)) 165 sys.sigmaE.value = GlobalFerm*sigmaE 166 sys.sigmaB.value = GlobalFerm*sigmaB 167 168 #boundary term parameters 169 sys.xi.value = sys.beta*(sys.dphi/(2*sys.H)) 170 sys.xieff.value = sys.xi + sys.sigmaB/(2*sys.H) 171 172 #acceleration for convenience 173 sys.ddphi.value = klein_gordon(sys.dphi, sys.dV(sys.phi), sys.H, -sys.G*sys.beta*sys.omega**2) 174 return 175 176def compute_timestep(t, y, sys, atol=1e-20, rtol=1e-6): 177 dydt = np.zeros(y.shape) 178 179 #odes for N and phi 180 dydt[0] = sys.H.value 181 dydt[1] = sys.dphi.value 182 dydt[2] = sys.ddphi.value 183 184 #achieving dlnkhdt is monotonous requires some care 185 dlnkhdt = dlnkh( sys.kh, sys.dphi, sys.ddphi, sys.beta, 186 0., sys.xi, sys.a, sys.H ) 187 r = 2*abs(sys.xi) 188 logfc = y[0] + np.log(r*dydt[0]) 189 dlnkhdt *= heaviside(dlnkhdt, 0)*heaviside(logfc, y[3]*(1-1e-5)) 190 dydt[3] = dlnkhdt 191 192 #ode for rhoChi 193 dydt[4] = drhoChi( sys.rhoChi, sys.E, sys.G, 194 sys.sigmaE, sys.sigmaB, sys.H ) 195 196 #compute boundary terms and then the gauge-field bilinear ODEs 197 Fcol = y[5:].shape[0]//3 198 F = y[5:].reshape(Fcol,3) 199 W = boundary_pai(float(sys.xi.value)) 200 dFdt = gauge_field_ode_schwinger( F, sys.a, sys.kh, 2*sys.H*sys.xieff, 201 sys.sigmaE, 1.0, W, dlnkhdt ) 202 #reshape to fit dydt 203 dydt[5:] = dFdt.reshape(Fcol*3) 204 205 return dydt 206 207 208#Event 1: Track the end of inflation: 209def condition_EndOfInflation(t, y, sys): 210 #compute energy densities 211 rhoV = sys.V(y[1]) 212 rhoK = y[2]**2/2 213 rhoEM = 0.5*(y[5]+y[6])*(sys.omega/sys.mu)**2*np.exp(4*(y[3]-y[0])) 214 rhoF = y[4]*(sys.omega/sys.mu)**2 215 216 #compute pressure 217 pV = -rhoV 218 pK = rhoK 219 pEM = 1/3*rhoEM 220 pF = 1/3*rhoF 221 222 return check_accelerated_expansion([rhoV, rhoK, rhoEM, rhoF], [pV, pK, pEM, pF])/(sys.H)**2 223 224def consequence_EndOfInflation(sys, occurance): 225 if occurance: 226 #stop solving once the end of inflation is reached 227 return "finish", {} 228 else: 229 #increase tend given the current Hubble rate 230 tdiff = np.round(5/sys.H, 0) 231 #round again, sometimes floats cause problems in t_span and t_eval. 232 tend = np.round(sys.t + tdiff, 0) 233 return "proceed", {"tend":tend} 234 235EndOfInflation = TerminalEvent("End of inflation", condition_EndOfInflation, -1, consequence_EndOfInflation) 236"""Defines the 'End of inflation' event.""" 237 238#Event 2: ensure that E^2 and B^2 are positive 239def condition_NegativeNorms(t, y, sys): 240 return min(y[5], y[6]) 241 242NegativeNorms : ErrorEvent = ErrorEvent("Negative norms", condition_NegativeNorms, -1, "Negative value for E^2 or B^2.") 243"""Defines the 'Negative norms' event.""" 244 245events = [EndOfInflation, NegativeNorms] 246 247 248#gather all information in the solver 249solver = GEFSolver(initial_conditions, update_values, compute_timestep, quantities, events) 250"""The solver used by the GEF model.""" 251 252#define mode-by-mode solver 253MbM = ModeSolver(mode_equation_SE_scale, {"a":a, "xi":xi, "H":H, "sigmaE":sigmaE, "sigmaB":sigmaB, "kS":kh}, 254 bd_classic, {}, default_atol=1e-5) 255"""The mode solver used by the GEF model.""" 256 257 258#define default docs for the above functions 259generate_docs(docs_models.DOCS)
The models name.
The model settings.
Possible settings are "mixed", "electric", "magnetic".
Determines if conductivities are computed assuming collinear E&M fields ("electric", "magnetic") or not ("mixed").
108def define_units(phi, dphi, V, rhoChi): 109 #compute Hubble rate at t0 110 rhoK = 0.5*dphi**2 111 rhoV = V(phi) 112 H0 = friedmann( rhoK, rhoV, rhoChi ) 113 114 omega = H0 #Characteristic frequency is the initial Hubble rate 115 mu = 1. #Charatcterisic amplitude is the Planck mass 116 117 return omega, mu
Define how initial data is used to set the reference frequency, $\omega$ and energy scale, $\mu$.
- energy scale: $M_{\rm P}$ in Planck units
- frequency scale: initial Hubble rate, $H_0$ (in Planck units)
120def initial_conditions(sys, ntr): 121 yini = np.zeros((ntr+1)*3+5) 122 123 #from the 'input' dictionary 124 yini[0] = sys.N.value 125 yini[1] = sys.phi.value 126 yini[2] = sys.dphi.value 127 128 #needs to be computed 129 sys.initialise("kh")( abs(sys.dphi)*sys.beta ) 130 yini[3] = np.log(sys.kh.value) 131 132 #initialise rhoChi 133 yini[4] = sys.rhoChi.value 134 135 #all gauge-field expectation values are assumed to be 0 at initialisation 136 return yini
Define how to create an array of initial data to solve the ODE's.
Parameters
- vals (BGSystem): contains initial data
- ntr (int): truncation number
Returns
- yini (NDArray): initial data in an array
139def update_values(t, y, sys, atol=1e-20, rtol=1e-6): 140 #spacetime variables 141 sys.t.value = t 142 sys.N.value = y[0] 143 sys.a.value = np.exp(y[0]) 144 145 #parse for convenience 146 sys.phi.value = y[1] 147 sys.dphi.value = y[2] 148 sys.kh.value = np.exp(y[3]) 149 150 sys.rhoChi.value = y[4] 151 152 #the gauge-field terms in y are not stored, save these values here 153 sys.E.value = y[5]*np.exp(4*(y[3]-y[0])) 154 sys.B.value = y[6]*np.exp(4*(y[3]-y[0])) 155 sys.G.value = y[7]*np.exp(4*(y[3]-y[0])) 156 157 #Hubble rate 158 sys.H.value = friedmann(0.5*sys.dphi**2, sys.V(sys.phi), 159 0.5*(sys.E+sys.B)*sys.omega**2, sys.rhoChi*sys.omega**2) 160 161 #conductivities 162 sigmaE, sigmaB, ks = conductivity(sys.a.value, sys.H.value, sys.E.value, 163 sys.B.value, sys.G.value, sys.omega) 164 sys.kS.value = ks 165 GlobalFerm = heaviside(np.log(ks), np.log(sys.a*sys.H)) 166 sys.sigmaE.value = GlobalFerm*sigmaE 167 sys.sigmaB.value = GlobalFerm*sigmaB 168 169 #boundary term parameters 170 sys.xi.value = sys.beta*(sys.dphi/(2*sys.H)) 171 sys.xieff.value = sys.xi + sys.sigmaB/(2*sys.H) 172 173 #acceleration for convenience 174 sys.ddphi.value = klein_gordon(sys.dphi, sys.dV(sys.phi), sys.H, -sys.G*sys.beta*sys.omega**2) 175 return
Compute static variables.
Parameters
- t (float): time
- y (float): array of data
- vals (BGSystem): system of data storing static variables
- atol, rtol (float): precisions (used for heaviside functions)
177def compute_timestep(t, y, sys, atol=1e-20, rtol=1e-6): 178 dydt = np.zeros(y.shape) 179 180 #odes for N and phi 181 dydt[0] = sys.H.value 182 dydt[1] = sys.dphi.value 183 dydt[2] = sys.ddphi.value 184 185 #achieving dlnkhdt is monotonous requires some care 186 dlnkhdt = dlnkh( sys.kh, sys.dphi, sys.ddphi, sys.beta, 187 0., sys.xi, sys.a, sys.H ) 188 r = 2*abs(sys.xi) 189 logfc = y[0] + np.log(r*dydt[0]) 190 dlnkhdt *= heaviside(dlnkhdt, 0)*heaviside(logfc, y[3]*(1-1e-5)) 191 dydt[3] = dlnkhdt 192 193 #ode for rhoChi 194 dydt[4] = drhoChi( sys.rhoChi, sys.E, sys.G, 195 sys.sigmaE, sys.sigmaB, sys.H ) 196 197 #compute boundary terms and then the gauge-field bilinear ODEs 198 Fcol = y[5:].shape[0]//3 199 F = y[5:].reshape(Fcol,3) 200 W = boundary_pai(float(sys.xi.value)) 201 dFdt = gauge_field_ode_schwinger( F, sys.a, sys.kh, 2*sys.H*sys.xieff, 202 sys.sigmaE, 1.0, W, dlnkhdt ) 203 #reshape to fit dydt 204 dydt[5:] = dFdt.reshape(Fcol*3) 205 206 return dydt
Compute time derivatives for dynamical variables.
Parameters
- t (float): time
- y (float): array of data
- vals (BGSystem): system of data storing static variables
- atol, rtol (float): precisions (used for heaviside functions)
Returns
- dydt (NDArray): time derivative of y
210def condition_EndOfInflation(t, y, sys): 211 #compute energy densities 212 rhoV = sys.V(y[1]) 213 rhoK = y[2]**2/2 214 rhoEM = 0.5*(y[5]+y[6])*(sys.omega/sys.mu)**2*np.exp(4*(y[3]-y[0])) 215 rhoF = y[4]*(sys.omega/sys.mu)**2 216 217 #compute pressure 218 pV = -rhoV 219 pK = rhoK 220 pEM = 1/3*rhoEM 221 pF = 1/3*rhoF 222 223 return check_accelerated_expansion([rhoV, rhoK, rhoEM, rhoF], [pV, pK, pEM, pF])/(sys.H)**2
Determine the end of inflation using $\ddot{a} = 0$
Parameters
- t (float): time
- y (float): array of data
- vals (BGSystem): system of data storing static variables
225def consequence_EndOfInflation(sys, occurance): 226 if occurance: 227 #stop solving once the end of inflation is reached 228 return "finish", {} 229 else: 230 #increase tend given the current Hubble rate 231 tdiff = np.round(5/sys.H, 0) 232 #round again, sometimes floats cause problems in t_span and t_eval. 233 tend = np.round(sys.t + tdiff, 0) 234 return "proceed", {"tend":tend}
Define how the solver response to a (non)-occurrence of the end of inflation.
If the event occurs, the solultion is accepted. Else, increase $t_{\rm end}$ and continue solving.
Parameters
- vals (BGSystem): solution to an ODE
- occurrence (bool): if the event has occurred during the ODE solution
Defines the 'End of inflation' event.
Defines the 'Negative norms' event.
The solver used by the GEF model.
The mode solver used by the GEF model.