geff.models.pai
$\newcommand{\bm}[1]{\boldsymbol{#1}}$ Defines the GEF model "pai" corresponding to pure axion inflation.
For more details on this model, see e.g., arXiv:2109.01651.
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}$
- 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$
- 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 "pai" corresponding to pure axion inflation. 4 5For more details on this model, see e.g., [arXiv:2109.01651](https://arxiv.org/abs/2109.01651). 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* static variables: 16 * `a` - *scale factor, $a$* 17 * `H` - *Hubble rate, $H$* 18 * `ddphi` - *inflaton acceleration, $\ddot{\varphi}$* 19 * `E`, `B`, `G` - *gauge-field expectation values, $\langle \bm{E}^2 \rangle$, $\langle \bm{B}^2 \rangle$, -$\langle \bm{E} \cdot \bm{B} \rangle$* 20 * `xi` - *instability parameter, $\xi$* 21* constants: 22 * `beta` - *coupling strength, $\beta$* 23* functions: 24 * `V`,`dV` - *inflaton potential, $V(\varphi)$, and its derivative, $V_{,\varphi}(\varphi)$* 25* gauge field: 26 * `GF` - *tower of gauge bilinears, $\mathcal{F}_{\mathcal X}^{(n)}$* 27 28The model expects the following input: 29* `phi`, `dphi` - *initial data on the inflaton, $\varphi$, $\dot\varphi$* 30* `rhoChi` - *initial data on the fermion energy density, $\rho_{\chi}$* 31* `beta` - *coupling strength, $\beta$* 32* `V`, `dV` - *potential shape, $V(\varphi)$, $V_{,\varphi}(\varphi)$* 33 34The model tracks the following events: 35* end of inflation - terminate solver when $\ddot{a} < 0$ 36* negative norms - return an error when $\langle \bm{E}^2 \rangle$ or $\langle \bm{B}^2 \rangle$ are negative 37""" 38import numpy as np 39 40from geff.bgtypes import t, N, a, H, phi, dphi, ddphi, V, dV, E, B, G, xi, kh, beta, GF 41from geff.solver import TerminalEvent, ErrorEvent, GEFSolver 42from geff.mbm import ModeSolver 43 44from geff.utility.eom import friedmann, gauge_field_ode, dlnkh, klein_gordon, check_accelerated_expansion 45from geff.utility.mode import bd_classic, mode_equation_classic 46from geff.utility.boundary import boundary_pai 47from geff.utility.general import heaviside 48from geff._docs import generate_docs, docs_models 49 50 51name : str = "PAI" 52"""The models name.""" 53 54quantities : dict={ 55 "time":[t], #time coordinate according to which EoMs are expressed 56 "dynamical":[N, phi, dphi, kh], #variables which evolve in time according to an EoM 57 "static":[a, H, ddphi, xi, E, B, G], #variables which are derived from dynamical variables 58 "constant":[beta], #constant quantities in the model 59 "function":[V, dV], #functions of variables such as scalar potentials 60 "gauge":[GF] #Gauge fields whose dynamics is given in terms of bilinear towers of expectation values 61 } 62 63#State which variables require input for initialisation 64model_input = [ beta, phi, dphi, V, dV] 65 66#this functions is called upon initialisation of the GEF class 67def define_units(phi, dphi, V): 68 #compute Hubble rate at t0 69 rhoK = 0.5*dphi**2 70 rhoV = V(phi) 71 H0 = friedmann( rhoK, rhoV ) 72 73 omega = H0 #Characteristic frequency is the initial Hubble rate in Planck units 74 mu = 1. #Charatcterisic amplitude is the Planck mass (in Planck units) 75 76 return omega, mu 77 78#define sys_to_yini for GEFSolver 79def initial_conditions(sys, ntr): 80 yini = np.zeros((ntr+1)*3+4) 81 82 #from the 'input' dictionary 83 yini[0] = sys.N.value 84 yini[1] = sys.phi.value 85 yini[2] = sys.dphi.value 86 87 #needs to be computed 88 sys.initialise("kh")( abs(sys.dphi)*sys.beta ) 89 90 #all gauge-field expectation values are assumed to be 0 at initialisation 91 return yini 92 93#define update_sys for GEFSolver 94def update_values(t, y, sys): 95 #spacetime variables 96 sys.t.value = t 97 sys.N.value = y[0] 98 sys.a.value = np.exp(y[0]) 99 100 #parse for convenience 101 sys.phi.value = y[1] 102 sys.dphi.value = y[2] 103 sys.kh.value = np.exp(y[3]) 104 105 #the gauge-field terms in y are not stored, save these values here 106 sys.E.value = y[4]*np.exp(4*(y[3]-y[0])) 107 sys.B.value = y[5]*np.exp(4*(y[3]-y[0])) 108 sys.G.value = y[6]*np.exp(4*(y[3]-y[0])) 109 110 #Hubble rate 111 sys.H.value = friedmann(0.5*sys.dphi**2, sys.V(sys.phi), 0.5*(sys.E+sys.B)*sys.omega**2) 112 113 #boundary term parameter 114 sys.xi.value = sys.beta*(sys.dphi/(2*sys.H)) 115 116 #acceleration for convenience 117 sys.ddphi.value = klein_gordon(sys.dphi, sys.dV(sys.phi), sys.H, -sys.G*sys.beta*sys.omega**2) 118 return 119 120#define timestep for GEFSolver 121def compute_timestep(t, y, sys): 122 123 dydt = np.zeros(y.shape) 124 125 #odes for N and phi 126 dydt[0] = sys.H.value 127 dydt[1] = sys.dphi.value 128 dydt[2] = sys.ddphi.value 129 130 #achieving dlnkhdt is monotonous requires some care 131 dlnkhdt = dlnkh( sys.kh, sys.dphi, sys.ddphi, sys.beta, 132 0., sys.xi, sys.a, sys.H ) 133 134 logfc = y[0] + np.log( 2*abs(sys.xi)*dydt[0]) 135 dlnkhdt *= heaviside(dlnkhdt,0)*heaviside(logfc,y[3]*(1-1e-5)) 136 dydt[3] = dlnkhdt 137 138 #compute boundary terms and then the gauge-field bilinear ODEs 139 Fcol = y[4:].shape[0]//3 140 F = y[4:].reshape(Fcol,3) 141 W = boundary_pai(sys.xi.value) 142 dFdt = gauge_field_ode(F, sys.a, sys.kh, 2*sys.H*sys.xi, W, dlnkhdt, L=20) 143 144 #reshape to fit dydt 145 dydt[4:] = dFdt.reshape(Fcol*3) 146 147 return dydt 148 149#Event 1: Track the end of inflation: 150def condition_EndOfInflation(t, y, sys): 151 #compute energy densities 152 rhoV = sys.V(y[1]) 153 rhoK = y[2]**2/2 154 rhoEM = 0.5*(y[4]+y[5])*(sys.omega/sys.mu)**2*np.exp(4*(y[3]-y[0])) 155 156 #compute pressure 157 pV = -rhoV 158 pK = rhoK 159 pEM = 1/3*rhoEM 160 161 return check_accelerated_expansion([rhoV, rhoK, rhoEM], [pV, pK, pEM])/(sys.H)**2 162 163def consequence_EndOfInflation(sys, occurrence): 164 if occurrence: 165 #stop solving once the end of inflation is reached 166 return "finish", {} 167 else: 168 #increase tend given the current Hubble rate 169 tdiff = np.round(5/sys.H, 0) 170 #round again, sometimes floats cause problems in t_span and t_eval. 171 tend = np.round(sys.t + tdiff, 0) 172 return "proceed", {"tend":tend} 173 174EndOfInflation : TerminalEvent = TerminalEvent("End of inflation", condition_EndOfInflation, -1, consequence_EndOfInflation) 175"""Defines the 'End of inflation' event.""" 176 177#Event 2: ensure that E^2 and B^2 are positive 178def condition_NegativeNorms(t, y, sys): 179 return min(y[4], y[5]) 180 181NegativeNorms : ErrorEvent = ErrorEvent("Negative norms", condition_NegativeNorms, -1, "Negative value for E^2 or B^2.") 182"""Defines the 'Negative norms' event.""" 183 184events = [EndOfInflation, NegativeNorms] 185 186#gather all information in the solver 187solver = GEFSolver(initial_conditions, update_values, compute_timestep, quantities, events) 188"""The solver used by the GEF model.""" 189 190#define mode-by-mode solver 191MbM = ModeSolver(mode_equation_classic, {"a":a,"xi":xi, "H":H}, bd_classic, {}) 192"""The mode solver used by the GEF model.""" 193 194 195#define default docs for the above functions 196generate_docs(docs_models.DOCS)
The models name.
68def define_units(phi, dphi, V): 69 #compute Hubble rate at t0 70 rhoK = 0.5*dphi**2 71 rhoV = V(phi) 72 H0 = friedmann( rhoK, rhoV ) 73 74 omega = H0 #Characteristic frequency is the initial Hubble rate in Planck units 75 mu = 1. #Charatcterisic amplitude is the Planck mass (in Planck units) 76 77 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)
80def initial_conditions(sys, ntr): 81 yini = np.zeros((ntr+1)*3+4) 82 83 #from the 'input' dictionary 84 yini[0] = sys.N.value 85 yini[1] = sys.phi.value 86 yini[2] = sys.dphi.value 87 88 #needs to be computed 89 sys.initialise("kh")( abs(sys.dphi)*sys.beta ) 90 91 #all gauge-field expectation values are assumed to be 0 at initialisation 92 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
95def update_values(t, y, sys): 96 #spacetime variables 97 sys.t.value = t 98 sys.N.value = y[0] 99 sys.a.value = np.exp(y[0]) 100 101 #parse for convenience 102 sys.phi.value = y[1] 103 sys.dphi.value = y[2] 104 sys.kh.value = np.exp(y[3]) 105 106 #the gauge-field terms in y are not stored, save these values here 107 sys.E.value = y[4]*np.exp(4*(y[3]-y[0])) 108 sys.B.value = y[5]*np.exp(4*(y[3]-y[0])) 109 sys.G.value = y[6]*np.exp(4*(y[3]-y[0])) 110 111 #Hubble rate 112 sys.H.value = friedmann(0.5*sys.dphi**2, sys.V(sys.phi), 0.5*(sys.E+sys.B)*sys.omega**2) 113 114 #boundary term parameter 115 sys.xi.value = sys.beta*(sys.dphi/(2*sys.H)) 116 117 #acceleration for convenience 118 sys.ddphi.value = klein_gordon(sys.dphi, sys.dV(sys.phi), sys.H, -sys.G*sys.beta*sys.omega**2) 119 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)
122def compute_timestep(t, y, sys): 123 124 dydt = np.zeros(y.shape) 125 126 #odes for N and phi 127 dydt[0] = sys.H.value 128 dydt[1] = sys.dphi.value 129 dydt[2] = sys.ddphi.value 130 131 #achieving dlnkhdt is monotonous requires some care 132 dlnkhdt = dlnkh( sys.kh, sys.dphi, sys.ddphi, sys.beta, 133 0., sys.xi, sys.a, sys.H ) 134 135 logfc = y[0] + np.log( 2*abs(sys.xi)*dydt[0]) 136 dlnkhdt *= heaviside(dlnkhdt,0)*heaviside(logfc,y[3]*(1-1e-5)) 137 dydt[3] = dlnkhdt 138 139 #compute boundary terms and then the gauge-field bilinear ODEs 140 Fcol = y[4:].shape[0]//3 141 F = y[4:].reshape(Fcol,3) 142 W = boundary_pai(sys.xi.value) 143 dFdt = gauge_field_ode(F, sys.a, sys.kh, 2*sys.H*sys.xi, W, dlnkhdt, L=20) 144 145 #reshape to fit dydt 146 dydt[4:] = dFdt.reshape(Fcol*3) 147 148 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
151def condition_EndOfInflation(t, y, sys): 152 #compute energy densities 153 rhoV = sys.V(y[1]) 154 rhoK = y[2]**2/2 155 rhoEM = 0.5*(y[4]+y[5])*(sys.omega/sys.mu)**2*np.exp(4*(y[3]-y[0])) 156 157 #compute pressure 158 pV = -rhoV 159 pK = rhoK 160 pEM = 1/3*rhoEM 161 162 return check_accelerated_expansion([rhoV, rhoK, rhoEM], [pV, pK, pEM])/(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
164def consequence_EndOfInflation(sys, occurrence): 165 if occurrence: 166 #stop solving once the end of inflation is reached 167 return "finish", {} 168 else: 169 #increase tend given the current Hubble rate 170 tdiff = np.round(5/sys.H, 0) 171 #round again, sometimes floats cause problems in t_span and t_eval. 172 tend = np.round(sys.t + tdiff, 0) 173 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.