diff --git a/Makefile b/Makefile index 9e4a8a779..8f58d3902 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,7 @@ endif %.o: %.c .base $(HEADERFILES) cd $(WRKDIR);$(CC) $(OPTFLAG) $(OMPFLAG) $(CCFLAG) $(INCLUDES) -c ../$< -o $*.o -TOOLS = growTable.o dei_rkck.o sparse.o evolver_rkck.o evolver_ndf15.o arrays.o parser.o quadrature.o hyperspherical.o common.o trigonometric_integrals.o +TOOLS = growTable.o dei_rkck.o sparse.o evolver_rkck.o evolver_rkdp45.o evolver_ndf15.o arrays.o parser.o quadrature.o hyperspherical.o common.o trigonometric_integrals.o SOURCE = input.o background.o thermodynamics.o perturbations.o primordial.o fourier.o transfer.o harmonic.o lensing.o distortions.o diff --git a/README.md b/README.md index c3efae43b..59f87911b 100644 --- a/README.md +++ b/README.md @@ -1,120 +1,51 @@ -CLASS: Cosmic Linear Anisotropy Solving System {#mainpage} +TriggerCLASS ============================================== +forked from CLASS by Julien Lesgourgues and Thomas Tram; see http://class-code.net and https://github.com/lesgourg/class_public -Authors: Julien Lesgourgues, Thomas Tram, Nils Schoeneberg +TriggerCLASS is a modification of CLASS that implements an instant phase transition in a new fluid component that goes from a cosmological constant phase to a decaying phase. The transition is triggered by a sub-dominant clock field that carries adiabatic fluctiations. As such, it describes the physics of the New Early Dark Energy (NEDE) and Hybrid Early Dark Energy model. The details of the implementation have been explained in the methodology part of https://arxiv.org/abs/2006.06686 and through many additional comments in the code tagged with "NEDE". -with several major inputs from other people, especially Benjamin -Audren, Simon Prunet, Jesus Torrado, Miguel Zumalacarregui, Francesco -Montanari, Deanna Hooper, Samuel Brieden, Daniel Meinert, Matteo Lucca, etc. +The version used for the publications ArXiv: 1910.10739, 2006.06686, 2009.00006 has been tagged with "NewEDEv3.0". +The version used for the publication ArXiv: 2209.02708 has been tagged with "NewEDEv4". -For download and information, see http://class-code.net +__New in version 7.0 [31 July 2024]__: Rebased TriggerCLASS on version 3.2.1 of class_public with the SHA 997d1ac0b64d11439948a0cc13f719ef427f87be (older versions of TriggerCLASS are based on the older version 2 of class_public). This comes with the following modifications: +* New precision parameters: In CLASS versions >3, the implicit ndf15 integrator is used for the background evolution. This automatically increases precision around the NEDE decay time, so the precision parameters "decay_res_enhancement" and "trigger_resolution" have been removed. +* Added a background approximation switching logic that splits up the background evolution into two phases (before and after the trigger fluid approximation). +Ultimately, version 7.0 is faster than v6.1 by a factor of about 10 in the background and between 5 and 8 in the perturbations. The two codes have been tested against each other, and produce similar results in Cls and matter power spectrum to within 5 permille, a difference coming from the LambdaCDM sector difference in the two CLASS codes. with the precision settings given in input/NewEDE.ini and the NEDE notebook in the notebooks directory. +__New in version 6.1 [7 May 2023]__: TriggerCLASS now allows for Omega0_NEDE_trigger_DM as input, controlling the trigger abundance today (which contributes to DM). -Compiling CLASS and getting started ------------------------------------ - -(the information below can also be found on the webpage, just below -the download button) - -Download the code from the webpage and unpack the archive (tar -zxvf -class_vx.y.z.tar.gz), or clone it from -https://github.com/lesgourg/class_public. Go to the class directory -(cd class/ or class_public/ or class_vx.y.z/) and compile (make clean; -make class). You can usually speed up compilation with the option -j: -make -j class. If the first compilation attempt fails, you may need to -open the Makefile and adapt the name of the compiler (default: gcc), -of the optimization flag (default: -O4 -ffast-math) and of the OpenMP -flag (default: -fopenmp; this flag is facultative, you are free to -compile without OpenMP if you don't want parallel execution; note that -you need the version 4.2 or higher of gcc to be able to compile with --fopenmp). Many more details on the CLASS compilation are given on the -wiki page - -https://github.com/lesgourg/class_public/wiki/Installation - -(in particular, for compiling on Mac >= 10.9 despite of the clang -incompatibility with OpenMP). +__New in version 5 [12 Oct 2022]__: TriggerCLASS now takes the decay redshift z_decay_NEDE (rather than the trigger mass) as input. The trigger mass is then determined via a shooting method. Output improvments and more detailed comments. -To check that the code runs, type: +__New in version 4 [20 Dec 2020]__: TriggerCLASS now accepts f_NEDE as input parameter (replaces Omega_NEDE). Introduced "tracking mode" for which the rest-frame sound speed equals the adiabatic sound speed (this feature has not been tested intensively yet). Output improvments and more detailed comments. - ./class explanatory.ini -The explanatory.ini file is THE reference input file, containing and -explaining the use of all possible input parameters. We recommend to -read it, to keep it unchanged (for future reference), and to create -for your own purposes some shorter input files, containing only the -input lines which are useful for you. Input files must have a *.ini -extension. We provide an example of an input file containing a -selection of the most used parameters, default.ini, that you may use as a -starting point. +Compiling TriggerCLASS and getting started +----------------------------------- -If you want to play with the precision/speed of the code, you can use -one of the provided precision files (e.g. cl_permille.pre) or modify -one of them, and run with two input files, for instance: +In order to install TriggerCLASS, clone the branch "NewEDEv4" in a new folder and follow the same steps as required for the installation of the base CLASS code detailed in https://github.com/lesgourg/class_public. Also see the Wiki page: - ./class test.ini cl_permille.pre +https://github.com/lesgourg/class_public/wiki/Installation -The files *.pre are suppposed to specify the precision parameters for -which you don't want to keep default values. If you find it more -convenient, you can pass these precision parameter values in your *.ini -file instead of an additional *.pre file. +For a successfull compilation adapt the compiler information in "Makefile" and "./python/setup.py". After compiling it, check that TriggerCLASS has been properly set up by running first + + ./class input/explanatory.ini -The automatically-generated documentation is located in +This corresponds to a standard LambdaCDM run. To check that the trigger component works correctly, type: - doc/manual/html/index.html - doc/manual/CLASS_manual.pdf + ./class input/NewEDE.ini -On top of that, if you wish to modify the code, you will find lots of -comments directly in the files. +This should result in a run with a non-vanishing fraction of NEDE. The output should provide a detailed account of the NEDE parameters. +The NewEDE.ini also explains the NEDE input parameters. -Python +MCMC analysis ------ -To use CLASS from python, or ipython notebooks, or from the Monte -Python parameter extraction code, you need to compile not only the -code, but also its python wrapper. This can be done by typing just -'make' instead of 'make class' (or for speeding up: 'make -j'). More -details on the wrapper and its compilation are found on the wiki page - -https://github.com/lesgourg/class_public/wiki - -Plotting utility ----------------- - -Since version 2.3, the package includes an improved plotting script -called CPU.py (Class Plotting Utility), written by Benjamin Audren and -Jesus Torrado. It can plot the Cl's, the P(k) or any other CLASS -output, for one or several models, as well as their ratio or percentage -difference. The syntax and list of available options is obtained by -typing 'pyhton CPU.py -h'. There is a similar script for MATLAB, -written by Thomas Tram. To use it, once in MATLAB, type 'help -plot_CLASS_output.m' - -Developing the code --------------------- - -If you want to develop the code, we suggest that you download it from -the github webpage - -https://github.com/lesgourg/class_public - -rather than from class-code.net. Then you will enjoy all the feature -of git repositories. You can even develop your own branch and get it -merged to the public distribution. For related instructions, check - -https://github.com/lesgourg/class_public/wiki/Public-Contributing - -Using the code --------------- - -You can use CLASS freely, provided that in your publications, you cite -at least the paper `CLASS II: Approximation schemes `. Feel free to cite more CLASS papers! +In order to perform a MCMC analysis, we recommend using MontePython, https://github.com/brinckmann/montepython_public, and follow their installation instructions. Our baseline MCMC run (as discussed in https://arxiv.org/abs/2006.06686) can be found under input/run_NEDE_canonical.param. To make it run, you first need to update MontePython with the files from the folder montepython_tree. In particular, this will update the data.py to translate the NEDE input parameters. The corresponding covariance matrix and bestfit file can be found in the respective subfolders covmat and bestfit. Support ------- -To get support, please open a new issue on the +To get support, please open a new issue on -https://github.com/lesgourg/class_public +https://github.com/NEDE-Cosmo/TriggerCLASS -webpage! diff --git a/explanatory.ini b/explanatory.ini deleted file mode 100644 index 0db900d7c..000000000 --- a/explanatory.ini +++ /dev/null @@ -1,1336 +0,0 @@ -# *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~* -# * CLASS input parameter file * -# *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~* - -# This example of input file, intended for CLASS beginners, lists all -# possibilities with detailed comments. You can use a more concise version, in -# which only the arguments in which you are interested would appear. Only lines -# containing an equal sign not preceded by a sharp sign "#" are considered by -# the code, any other line is considered as a comment. -# -# The normal syntax is: parameter = value(s) -# where white spaces do not matter (they are removed automatically by the -# parser unless they are part of the parameter name). -# However, 'parameter' = value(s) -# and "parameter" = value(s) -# are also accepted by the parser since v2.8.0 -# -# Input files must have an extension ".ini". - - - -# ------------------------- -# ----> General parameters: -# ------------------------- - -# 1) List of output spectra requested: -# - 'tCl' for temperature Cls, -# - 'pCl' for polarization Cls, -# - 'lCl' for CMB lensing potential Cls, -# - 'nCl' (or 'dCl') for density number count Cls, -# - 'sCl' for galaxy lensing potential Cls, -# - 'mPk' for total matter power spectrum P(k) infered from gravitational -# potential, -# - 'dTk' (or 'mTk') for density transfer functions for each species, -# - 'vTk' for velocity transfer function for each species -# - 'sd' for spectral distortions -# Warning: both lCl and sCl compute the C_ls of the lensing potential, -# C_l^phi-phi. If you are used to other codes, you may want to deal instead -# with the deflection Cls or the shear/convergence Cls. The relations -# between them are trivial: -# --> deflection d: Cl^dd = l(l+1) C_l^phiphi -# --> convergence kappa and shear gamma: the share the same harmonic -# power spectrum: Cl^gamma-gamma = 1/4 * [(l+2)!/(l-2)!] C_l^phi-phi -# By defaut, the code will try to compute the following cross-correlation -# Cls (if available): temperature-polarisation, temperature-CMB lensing, -# polarization-CMB lensing, CMB lensing-density, and density-lensing. Other -# cross-correlations are not computed because they would slow down the -# code considerably. -# -# Can be left blank if you do not want to evolve cosmological perturbations -# at all. (default: set to blank, no perturbation calculation) -output = tCl,pCl,lCl,mPk -#output = tCl,pCl,lCl -#output = mPk,mTk -#output = Sd - -# 1.a) If you included 'tCl' in the list, you can take into account only some -# of the terms contributing to the temperature spectrum: -# - intrinsic temperature corrected by Sachs-Wolfe ('tsw' or 'TSW'), -# - early integrated Sachs-Wolfe ('eisw' or 'EISW'), -# - late integrated Sachs-Wolfe ('lisw' or 'LISW'), -# - Doppler ('dop' or 'Dop'), -# - polarisation contribution ('pol' or 'Pol'). -# Put below the list of terms to be included (defaut: if this field is not -# passed, all terms will be included) -#temperature_contributions = tsw, eisw, lisw, dop, pol - -# 1.a.1) If one of 'eisw' or 'lisw' is turned off, the code will read -# 'early/late isw redshift', the split value of redshift z at which the -# isw is considered as late or early (if this field is absent or left -# blank, by default, 'early/late isw redshift' is set to 50) -#early_late_isw_redshift = - -# 1.b) If you included 'nCl' (or 'dCl') in the list, you can take into account -# only some of the terms contributing to the obsevable number count -# fluctuation spectrum: -# - matter density ('density'), -# - redshift-space and Doppler distortions ('rsd'), -# - lensing ('lensing'), -# - or gravitational potential terms ('gr'). -# Put below the list of terms to be included (defaut: if this field is not -# passed, only 'dens' will be included) -#number_count_contributions = density, rsd, lensing, gr - -# 1.c) If you included 'dTk' (or 'mTk') in the list, the code will give you by -# default the transfer function of the scale-invariant Bardeen potentials -# (for whatever gauge you are using). If you need the transfer function of -# additional metric fluctuations, specific to the gauge you are using, set -# the following flag to 'yes' (default: set to 'no') -#extra_metric_transfer_functions = yes - - -# 2) If you want to consider perturbed recombination, enter a word -# containing the letter 'y' or 'Y'. CLASS will then compute the -# perturbation in the ionization fraction x_e and the baryon -# temperature, as in 0707.2727. The initial conformal time will be -# small, therefore you should use the default integrator ndf15 -# (i.e. do not set 'evolver' to 0, otherwise the code will be -# slower). (default: no, neglect perturbed recombination) -#perturbed_recombination = yes - -# 3) List of modes: -# - 's' for scalars, -# - 'v' for vectors, -# - 't' for tensors). -# More than one letter allowed, can be attached or separated by arbitrary -# characters; letters can be small or capital. (default: set to 's') -modes = s -#modes = s,t - -# 3.a) List of initial conditions for scalars: -# - 'ad' for adiabatic, -# - 'bi' for baryon isocurvature, -# - 'cdi' for CDM isocurvature, -# - 'nid' for neutrino density isocurvature, -# - 'niv' for neutrino velocity isocurvature. -# More than one of these allowed, can be attached or separated by arbitrary -# characters; letters can be small or capital. (default: set to 'ad') -ic = ad -#ic = ad&bi&nid - -# 3.b) Which perturbations should be included in tensor calculations? -# - write 'exact' to include photons, ultra-relativistic species 'ur' -# and all non-cold dark matter species 'ncdm'; -# - write 'massless' to approximate 'ncdm' as extra relativistic species -# (good approximation if ncdm is still relativistic at the time of -# recombination); -# - write 'photons' to include only photons -# (default: set to 'massless') -tensor_method = - - -# 4) Gauge -# 4.a) Gauge in which calculations are performed: -# - 'sync' or 'synchronous' or 'Synchronous' for synchronous, -# - 'new' or 'newtonian' or 'Newtonian' for Newtonian/longitudinal gauge -# (default: set to synchronous) -gauge = synchronous - -# 4.b) Do you want to output the N-body gauge quantities as well? -# If you included 'dTk' or 'vTk' in the list of outputs, you may transform -# your transfer functions into the Nbody gauge by setting the following -# flag to 'yes'. This will also include the transfer function for the -# metric perturbations H_T' (exact) and gamma (approximate) in the Nbody gauge. -# See e.g. 1505.04756, and equations (A.2) and (A.5) in 1811.00904 -# for more precise definitions. These calculations are more stable with -# 'gauge=synchronous' (default). To compute H_T' and gamma -# without converting the output to the Nbody gauge, -# please use the flag 'extra metric transfer functions' instead. -# Can be set to anything starting with 'y' or 'n'. -# (default: set to 'no') -#nbody_gauge_transfer_functions = yes - -# 5) Hubble parameter : either 'H0' in km/s/Mpc or 'h' (or 'theta_s_100'), where -# the latter is the peak scale parameter defined exactly as 100(ds_dec/da_dec) -# with a decoupling time given by maximum of visibility function (quite different -# from theta_MC of CosmoMC and slightly different from theta_* of CAMB) -# (default: 'h' set to 0.67810 such that 100*theta_s = 1.041783 like in Planck 2018) -h = 0.67810 -#H0 = 67.810 -#theta_s_100 = 1.041783 - - -# 6) Primordial Helium fraction 'YHe', e.g. 0.25; if set to 'BBN' or 'bbn', -# will be inferred from Big Bang Nucleosynthesis (default: set to 'BBN') -YHe = BBN - - -# 7) 'recombination' algorithm set to 'RECFAST' or 'HyRec'. 'HyRec' points at HyRec 2020. Its compute time is negligible compared to other CLASS modules. 'RECFAST' points at RecFastCLASS, an enhanced version of RecFast 1.5 with better integration shceme and less discontinuities. Recfast is still slightly faster than HyRec but less accurate. HyRec is better for most purposes. RecFast can still be useful for studying some particular modifications of standard recombination. Both schemes use the CLASS ODE integrators. (Default: HyRec') -recombination = HyRec - -# 7.a) If recombination algorithm is set to 'RECFAST' -# the photo-ionization coefficients beta(T) for normal Recfast depend on Tmat -# This is an approximation (see e.g. arxiv:1605.03928 page 10, arxiv:1503.04827 page 2, right column) -# With 'recfast_photoion_dependence' the photo-ionization coefficient beta(T) is set to depend on -# - 'Tmat' uses beta(Tmat) depending on matter temperature -# (like in original RECFAST and in CLASS v2.x) -# - 'Trad' uses beta(Trad) depending on radiation temperature -# (while this option is theoretically more motivated, the option 'Tmat' leads to -# results which agree better with HyRec and CosmoRec. This is probably due to the -# fudge factor for the Peebles coefficient being optimized for a Tmat dependence) -# (default: set to 'Tmat') -recfast_photoion_dependence = - - -# 8) Parametrization of reionization: 'reio_parametrization' must be one of -# - 'reio_none' (no reionization), -# - 'reio_camb' (like CAMB: one tanh() step for hydrogen reionization one -# for second helium reionization), -# - 'reio_bins_tanh' (binned history x_e(z) with tanh() interpolation -# between input values), -# - 'reio_half_tanh' (like 'reio_camb' excepted that we match the -# function xe(z) from recombination with only half a tanh(z-z_reio)), -# - 'reio_many_tanh' (arbitrary number of tanh-like steps with specified -# ending values, a scheme usually more useful than 'reio_bins_tanh'), -# - 'reio_inter' (linear interpolation between discrete values of xe(z)). -# (default: set to 'reio_camb') -reio_parametrization = reio_camb - -# 8.a) If 'reio_parametrization' set to 'reio_camb' or 'reio_half_tanh': -# enter one of 'z_reio' or 'tau_reio' (default: 'z_reio' set to 7.6711 to -# get tau_reio of 0.054308), plus 'reionization_exponent', -# 'reionization_width', 'helium_fullreio_redshift', -# 'helium_fullreio_width'. (default: set to 1.5, 0.5, 3.5, 0.5) -z_reio = 7.6711 -#tau_reio = 0.05430842 -reionization_exponent = 1.5 -reionization_width = 0.5 -helium_fullreio_redshift = 3.5 -helium_fullreio_width = 0.5 - -# 8.b) If 'reio_parametrization' set to 'reio_bins_tanh': -# enter number of bins and list of z_i and xe_i defining the free electron -# density at the center of each bin. Also enter a dimensionless paramater -# regulating the sharpness of the tanh() steps, independently of the bin -# width; recommended sharpness is 0.3, smaller values will make steps too -# sharp, larger values will make the step very progressive but with -# discontinuity of x_e(z) derivative around z_i values. (default: set to -# 0, blank, blank, 0.3) -binned_reio_num = 3 -binned_reio_z = 8,12,16 -binned_reio_xe = 0.8,0.2,0.1 -binned_reio_step_sharpness = 0.3 - -# 8.c) If 'reio_parametrization' set to 'reio_many_tanh': -# enter number of jumps, list of jump redhsifts z_i (central value of each -# tanh()), list of free electron density x_i after each jump, and common -# width of all jumps. If you want to end up with all hydrogen reionized -# but neglecting helium reionization, the first value of x_i in the list -# should be 1. For each x_i you can also pass the flags -1 or -2. They -# mean: -# - -1: after hydrogen + first helium recombination (so the code will -# substitute a value bigger than one based on Y_He); -# - -2: after hydrogen + second helium recombination (the code will -# substitute an even bigger value based on Y_He). -# You can get results close to reio_camb by setting these parameters to -# the value showed below (and adapting the second many_tanh_z to the usual -# z_reio). (default: not set) -many_tanh_num = 2 -many_tanh_z = 3.5,11.3 -many_tanh_xe = -2,-1 -many_tanh_width = 0.5 - -# 8.d) If 'reio_parametrization' set to 'reio_inter': enter the number of -# points, the list of redshifts z_i, and the list of free electron -# fraction values x_i. The code will do linear interpolation between them. -# The first z_i should always be 0. Like above, for each x_i, you can also -# pass the flags -1 or -2. They mean: for -1, after the hydrogen and the -# first helium recombination (so the code will substitute a value bigger -# than one based on Y_He); for -2, after the hydrogen and the second -# helium recombination (the code will substitute an even bigger value -# based on Y_He). The last value of x_i should always be zero, the code -# will substitute it with the value that one would get in absence of -# reionization, as computed by the recombination code. (default: not set) -reio_inter_num = 8 -reio_inter_z = 0, 3, 4, 8, 9, 10, 11, 12 -reio_inter_xe = -2, -2, -1, -1, 0.9, 0.5, 0.1, 0 - - -# 9) State whether you want the code to compute the simplest analytic -# approximation to the photon damping scale (it will be added to the -# thermodynamics output, and its value at recombination will be stored and -# displayed in the standard output) (default: 'compute damping scale' set to -# 'no') -compute_damping_scale = - - -# 10) State whether you want to include a variation of fudamental constants. Can be set to 'none' or to 'instantaneous'. Smoother evolutions could be included by modifying the function "background_varconst_of_z" in source/background.c. -varying_fundamental_constants = none - -# 10.a) If 'varying_fundamental_constants' is set to 'instantaneous', select the redshift of the transition 'varying_transition_redshift' (default: 50). At lower redshift, the value will be the currently observed value, while at higher redshift you can specify how large the value should be by giving the ratio of the value at high redshift with respect to the currently observed one. Provide the relative value of the fine structure constant 'varying_alpha' (default: 1), and the relative value of the effective electron mass 'varying_me' (default: 1). The treatment corresponds to that of 1705.03925. -varying_transition_redshift = -varying_alpha = 1. -varying_me = 1. - -# 10.b) If 'varying_fundamental_constants' is not set to 'none' and 'YHe' is set to 'BBN', specify by how much the 'YHe' prediction from 'BBN' should be affected by the different value of the fine structure constant. The default value is motivated by 2001.01787. (default: 1) -bbn_alpha_sensitivity = 1. - - -# ------------------------- -# ----> Species parameters: -# ------------------------- - -# 1) Photon density: either 'T_cmb' in K or 'Omega_g' or 'omega_g' (default: -# 'T_cmb' set to 2.7255) -T_cmb = 2.7255 -#Omega_g = -#omega_g = - - -# 2) Baryon density: either 'Omega_b' or 'omega_b' (default: 'omega_b' set to -# 0.02238280) -omega_b = 0.02238280 -#Omega_b = - - -# 3) Ultra-relativistic species / massless neutrino density: either -# 'N_ur' or 'Omega_ur' or 'omega_ur' (default: 'N_ur' set to 3.044; -# see 2008.01074 and 2012.02726. This value is more accurate than the -# previous default value of 3.046) (note: instead of 'N_ur' you can -# pass equivalently 'N_eff', although this syntax is deprecated) (one -# more remark: if you have respectively 1,2,3 massive neutrinos, if -# you stick to the default value T_ncdm equal to 0.71611, designed to -# give m/omega of 93.14 eV, and if you want to use N_ur to get N_eff -# equal to 3.044 in the early universe, then you should pass here -# respectively 2.0308,1.0176,0.00441) -N_ur = 3.044 -#Omega_ur = -#omega_ur = - -# 3.a) To simulate ultra-relativistic species with non-standard properties, you -# can pass 'ceff2_ur' and 'cvis2_ur' (effective squared -# sound speed and viscosity parameter, like in the Generalised Dark Matter -# formalism of W. Hu) (default: both set to 1/3) -#ceff2_ur = -#cvis2_ur = - - -# 4) Density of cdm (cold dark matter): 'Omega_cdm' or 'omega_cdm', or, -# density of total non-relativistic matter: 'Omega_m' or 'omega_m'. -# If you pass 'Omega_m' or 'omega_m', the code will automatically fill -# up the density of Cold Dark Matter such that all non-relativistic species -# (including non-cold DM) sum up to your input value of Omega_m -# (default: 'omega_cdm' set to 0.1201075) -omega_cdm = 0.1201075 -#Omega_cdm = -#Omega_m = -#omega_m = - - -# 5) ncdm sector (i.e. any non-cold dark matter relics, including massive -# neutrinos, warm dark matter, etc.): -# 5.a) 'N_ncdm' is the number of distinct species (default: set to 0) -N_ncdm = - -# 5.b) 'use_ncdm_psd_files' is the list of N_ncdm numbers: -# - 0 means 'phase-space distribution (psd) passed analytically -# inside the code, in the mnodule background.c, inside the function -# background_ncdm_distribution()', -# - 1 means 'psd passed as a file with at list two columns: first for -# q, second for f_0(q)', where q is p/T_ncdm -# (default: only zeros) -#use_ncdm_psd_files = 0 - -# 5.b.1) If some of the previous values are equal to one, 'ncdm_psd_filenames' is -# the list of names of psd files (as many as number of ones in previous -# entry) -ncdm_psd_filenames = psd_FD_single.dat - -# 5.c) 'ncdm_psd_parameters' is an optional list of double parameters to -# describe the analytic distribution function or to modify a p.s.d. passed -# as a file. It is made available in the routine -# background_ncdm_distribution. -#ncdm_psd_parameters = 0.3 ,0.5, 0.05 -#ncdm_psd_parameters = Nactive, sin^2_12 ,s23 ,s13 - -# 5.d) 'Omega_ncdm' or 'omega_ncdm' or 'm_ncdm' in eV (default: all set to -# zero); with only one of these inputs, CLASS computes the correct value -# of the mass; if both (Omega_ncdm, m_ncdm) or (omega_ncdm, m_ncdm) are -# passed, CLASS will renormalise the psd in order to fulfill both -# conditions. Passing zero in the list of m_ncdm's or Omeg_ncdm's means -# that for this component, this coefficient is not imposed, and its value -# is inferred from the other one. -m_ncdm = 0.06 -#m_ncdm = 0.04, 0.04, 0.04 -#Omega_ncdm = -#omega_ncdm = - -# 5.e) 'T_ncdm' is the ncdm temperature in units of photon temperature -# (default: set to 0.71611, which is slightly larger than the -# instantaneous decoupling value (4/11)^(1/3); indeed, this default value -# is fudged to give a ratio m/omega equal to 93.14 eV for active -# neutrinos, as predicted by precise studies of active neutrino -# decoupling, see hep-ph/0506164) -T_ncdm = - -# 5.f) 'ksi_ncdm' is the ncdm chemical potential in units of its own -# temperature (default: set to 0) -ksi_ncdm = - -# 5.g) 'deg_ncdm' is the degeneracy parameter multiplying the psd: 1 stands for -# 'one family', i.e. one particle + anti-particle (default: set to 1.0) -deg_ncdm = - -# 5.h) 'ncdm_quadrature_strategy' is the method used for the momentum sampling of -# the ncdm distribution function. -# - 0 is the automatic method, -# - 1 is Gauss-Laguerre quadrature, -# - 2 is the trapezoidal rule on [0,Infinity] using the transformation q->1/t-1. -# - 3 is the trapezoidal rule on [0,q_max] where q_max is the next input. -# (default: set to 0) -ncdm_quadrature_strategy = - -# 5.h.1) 'ncdm_maximum_q' is the maximum q relevant only for Quadrature strategy 3. -# (default: set to 15) -ncdm_maximum_q = - -# 5.h.2) Number of momentum bins. (default: 150) -ncdm_N_momentum_bins = - - -# 6) Curvature: 'Omega_k' (default: 'Omega_k' set to 0) -Omega_k = 0. - - -# Begin of ADDITIONAL SPECIES --> Add your species here - -# 7.1) Decaying CDM into Dark Radiation -# 7.1.a) The current fractional density of dcdm+dr (decaying cold dark matter -# and its relativistic decay radiation): 'Omega_dcdmdr' or 'omega_dcdmdr' -# (default: 'Omega_dcdmdr' set to 0) -Omega_dcdmdr = 0.0 -#omega_dcdmdr = 0.0 - -# 7.1.b) The rescaled initial value for dcdm density (see 1407.2418 for -# definitions). If you specify 7.a.1, 7.a.2 will be found automtically by a -# shooting method, and vice versa. (default: 'Omega_dcdmdr' set to 0, -# hence so is 'Omega_ini_dcdm') -#Omega_ini_dcdm = -#omega_ini_dcdm = - -# 7.1.c) Decay constant of dcdm in km/s/Mpc, same unit as H0 above. -Gamma_dcdm = 0.0 -tau_dcdm = 0.0 - - -# 7.2) Multi-interacting Dark Matter (idm), implemented by N. Becker, -# D.C. Hooper, and N. Schoeneberg. Described in (2010.04074) - -# 7.2.1) Global parameters for the (multi-)interacting Dark Matter component - -# 7.2.1.a) Amount of interacting Dark Matter -# Can be passed as either f_idm (fraction) or Omega_idm (relative abundance) (default : 0) -#Omega_idm = 0. -f_idm = 0. - -# 7.2.1.b) Mass of interacting Dark Matter particle in eV (default : 1e9) -m_idm = 1e9 - -# 7.2.2) Dark Matter interacting with Dark Radiation (idm_dr) and -# interacting Dark Radiation (idr), implemented by -# M. Archidiacono, S. Bohr, and D.C. Hooper, following the ETHOS -# framework (1512.05344). Can also take as input the parameters -# of the models of 1507.04351 (with non-abelian dark matter, dark -# gluons...) which can be seen as a sub-class of ETHOS. See -# 1907.01496 for more details on both cases. - -# 7.2.2.a) Amount of interacting dark radiation (idr) -# - Can be parameterised through the temperature ratio 'xi_idr' (= T_idr/T_cmb) -# - Can be parameterised through the number of extra relativistic relics 'N_idr' (or indifferently 'N_dg') -# In all cases the parameter is dimensionless. -# (default : 0) -xi_idr = -#N_idr = - -# 7.2.2.b) Statistical factor to differentiate between fermionic (= 7/8) and bosonic (= 1) dark radiation (default 7/8) -stat_f_idr = 0.875 - -# 7.2.2.c) Strength of the coupling between DM and DR: -# -# Can be passed as 'a_idm_dr' or 'a_dark' in ETHOS parameterisation, in units of 1/Mpc. -# Then in ETHOS notations: Gamma_DR-DM = - omega_DM a_dark ((1+z)/10^7)^nindex_dark -# while: Gamma_DM-DR = - 4/3 (rho_DR/rho_DM) omega_DM a_dark ((1+z)/10^7)^nindex_dark -# = - 4/3 omega_DR a_dark (1+z) ((1+z)/10^7)^nindex_dark -# or in CLASS notations: dmu_idm_dr = - Gamma_DR-DM = omega_idm_dr a_idm_dr ((1+z)/10^7)^nindex_idm_dr -# -# Can be passed as 'Gamma_0_nadm' in NADM parameterisation, in units of 1/Mpc. -# Then in ETHOS notations: Gamma_DR-DM = - 3/4 Omega_DM/Omega_DR Gamma_0_nadm -# while: Gamma_DM-DR = - (1+z) Gamma_0_nadm -# or in CLASS notations: dmu_idm_dr = - Gamma_DR-DM = 3/4 Omega_idm_dr/Omega_idr Gamma_0_nadm -# -# (default : 0) -a_idm_dr = 0. -#Gamma_0_nadm = - -# 7.2.2.d) Only if ETHOS parametrization : Power of the temperature dependence of the co-moving idr - idm_dr interaction rate -# Can be passed indifferently as 'nindex_idm_dr' (or 'nindex_dark'), in units of 1/Mpc. -# (default : 4, unless Gamma_0_nadm has been passed, then default changes to 0) -nindex_idm_dr = - -# 7.2.2.e) Only if ETHOS parametrization : Nature of the interacting dark radiation: 'free_streaming' or 'fluid' -# (default = 'free_streaming', unless Gamma_0_nadm has been passed, then default changes to 'fluid') -idr_nature = - -# 7.2.2.f) Strength of the dark radiation self interactions coupling, -# can be passed as 'b_idr' or 'b_dark', in units of 1/Mpc. -# In ETHOS notations: Gamma_DR-DR = (b_dark/a_dark) (Omega_DR/Omega_DM) Gamma_DR-DM -# In CLASS notations: dmu_idr = - Gamma_DR-DR = (b_idr/a_idm_dr) (Omega_idr/Omega_idm_dr) dmu_idm_dr -# (default : 0) -b_idr = - -# 7.2.2.g) idr - idm_dr interaction angular coefficient: 'alpha_idm_dr' (or indifferently 'alpha_dark') -# Should be 3/4 if vector boson mediator; 3/2 if scalar boson mediator. -# In full generality this coefficient may depend on l = 2, 3, 4... -# The user can pass here a list of values with an arbitrary size. The first coefficients will be adjusted -# accordingly. After that, the last value will be repeated. -# For instance, if users passes 3, 2, 1, the code will take alpha_2=3, alpha_3=2, and all others equal to 1. -# (default = all set to 1.5) -alpha_idm_dr = 1.5 - -# 7.2.2.h) idr self-interaction angular coefficient: 'beta_idr' (or indifferently 'beta_dark') -# In full generality this coefficient may depend on l = 2, 3, 4... -# The user can pass here a list of values with an arbitrary size. The first coefficients will be adjusted -# accordingly. After that, the last value will be repeated. -# For instance, if users passes 3, 2, 1, the code will take beta_2=3, beta_3=2, and all others equal to 1. -# (default = all set to 1.5) -beta_idr = 1.5 - -# -> Precision parameters for idm_dr and idr can be found in precisions.h, with the tag idm_dr - -# 7.2.3) Interacting Dark Matter with Baryons -# Implemented by D.C. Hooper, N. Schoeneberg, and N. Becker -# following 1311.2937, 1509.00029, 1803.09734, 1802.06788 - -# 7.2.3.a) Coupling strength of Dark Matter and baryons (in cm^2) (default : 0) -cross_idm_b = 0. -# 7.2.3.b) Temperature dependence of the DM - baryon interactions (between -4 and 4) (default : 0) -n_index_idm_b = 0 - -# 7.2.4) Dark Matter interactions with photons -# Implementd by N. Becker following the formalism of Stadler&Boehm (1802.06589) - -# 7.2.4.a) Interaction coefficient or coupling strength between DM and photons -# Can be passed as either u_idm_g (dimensionless interaction strength) or cross_idm_g (cross section in cm^2) (default : 0) -u_idm_g = 0 -#cross_idm_g = 0 - -# 7.2.4.b) Temperature dependence of the DM - photon interactions (default : 0) -n_index_idm_g = 0 - -# End of ADDITIONAL SPECIES - - -# 8) Dark energy contributions. -# At least one out of three conditions must be satisfied: -# - 'Omega_Lambda' unspecified. -# - 'Omega_fld' unspecified. -# - 'Omega_scf' set to a negative value. [Will be refered to as -# unspecified in the following text.] -# The code will then use the first unspecified component to satisfy the -# closure equation (sum_i Omega_i) equals (1 + Omega_k) -# (default: 'Omega_fld' and 'Omega_scf' set to 0 and 'Omega_Lambda' -# inferred by code) -Omega_fld = 0 -Omega_scf = 0 -# Omega_Lambda = 0.7 - -# 8.a) If Omega fluid is different from 0 - -# 8.a.1) The flag 'use_ppf' is 'yes' by default, to use the PPF approximation -# (see 0808.3125 [astro-ph]) allowing perturbations to cross the -# phantom divide. Set to 'no' to enforce true fluid equations for -# perturbations. When the PPF approximation is used, you can choose the -# ratio 'c_gamma_over_c_fld' (eq. (16) in 0808.3125). The default is 0.4 -# as recommended by that reference, and implicitely assumed in other -# codes. (default: 'use_ppf' to yes, 'c_gamma_over_c_fld' to 0.4) -use_ppf = yes -c_gamma_over_c_fld = 0.4 - -# 8.a.2) Choose your equation of state between different models, -# - 'CLP' for p/rho = w0_fld + wa_fld (1-a/a0) -# (Chevalier-Linder-Polarski), -# - 'EDE' for early Dark Energy -# (default:'fluid_equation_of_state' set to 'CLP') -fluid_equation_of_state = CLP - -# 8.a.2.1) Equation of state of the fluid in 'CLP' case and squared sound speed -# 'cs2_fld' of the fluid (this is the sound speed defined in the frame -# comoving with the fluid, i.e. obeying to the most sensible physical -# definition). Generalizing w(a) to a more complicated expressions would -# be easy, for that, have a look into source/background.c at the -# function background_w_fld(). (default: 'w0_fld' set to -1, 'wa_fld' to -# 0, 'cs2_fls' to 1) -#w0_fld = -0.9 -#wa_fld = 0. -#cs2_fld = 1 - -# 8.a.2.2) Equation of state of the fluid in 'EDE' case and squared sound speed -# 'cs2_fld' of the fluid (this is the sound speed defined in the frame -# comoving with the fluid, i.e. obeying to the most sensible physical -# definition). Generalizing w(a) to a more complicated expressions would -# be easy, for that, have a look into source/background.c at the -# function background_w_fld(). (default: 'w0_fld' set to -1, 'Omega_EDE' -# to 0, 'cs2_fls' to 1) -#w0_fld = -0.9 -#Omega_EDE = 0. -#cs2_fld = 1 - -# 8.b) If Omega scalar field is different from 0 - -# 8.b.1) Scalar field (scf) potential parameters and initial conditions -# (scf_parameters = [scf_lambda, scf_alpha, scf_A, scf_B, phi, -# phi_prime]). V = ((\phi-B)^\alpha + A)exp(-lambda*phi), see -# http://arxiv.org/abs/astro-ph/9908085. If 'attractor_ic_scf' is set to -# 'no', the last two entries are assumed to be the initial values of phi -# in units of the reduced planck mass m_Pl and the conformal time -# derivative of phi in units of [m_Pl/Mpc]. (Note however that CLASS -# determines the initial scale factor dynamically and the results might -# not be as expected in some models.) -scf_parameters = 10.0, 0.0, 0.0, 0.0, 100.0, 0.0 - -# 8.b.2) Scalar field (scf) initial conditions from attractor solution (assuming -# pure exponential potential). (default: yes) -attractor_ic_scf = yes - -# 8.b.3) Scalar field (scf) shooting parameter: If Omega_scf is set (can only be negative), -# the following index (0,1,2,...) in the list scf_parameters will be used for shooting: -# (See also the section about shooting in input.c) -# Basically parameter number scf_tuning_index will be adjusted until -# the correct Omega_scf is found to suffice the budget equation -scf_tuning_index = 0 - - -# 8.b.4) Scalar field (scf) shooting parameter. With this, you can overwrite some parameter -# of 8.b.1) depending on the index defined in 8.b.3) -scf_shooting_parameter = - -# ----------------------------------------- -# ----> Exotic energy injection parameters: -# ----------------------------------------- - -# 1) DM Annihilation - -# 1.a) In order to model energy injection from DM annihilation, specify a -# parameter 'annihilation_efficiency' corresponding to -# / m_cdm expressed here in units of m^3/s/J. Alternatively, -# you can specify the annihilation cross section in cm^3/s and the DM -# mass in GeV. The code will then evaluate 'annihilation_efficiency'. -# (default: all set to zero) -DM_annihilation_efficiency = 0. -#DM_annihilation_cross_section = 0. -#DM_annihilation_mass = 0. -#DM_annihilation_fraction = 0. - -# 1.a.1) You can model simple variations of the above quantity as a function of -# redhsift. If 'annihilation_variation' is non-zero, the function F(z) -# defined as ( / m_cdm)(z) (see 1.a) will be a parabola in log-log scale -# between 'annihilation_zmin' and 'annihilation_zmax', with a curvature -# given by 'annihilation_variation' (must be negative), and with a maximum -# in 'annihilation_zmax'; it will be constant outside this range. To -# take DM halos into account, specify the parameters 'annihilation_f_halo', -# the amplitude of the halo contribution, and 'annihilation_z_halo', -# the characteristic redshift of halos (default: no variation, -# 'annihilation_variation' and 'annihilation_f_halo' set to zero). -DM_annihilation_variation = 0. -DM_annihilation_z = 1000 -DM_annihilation_zmax = 2500 -DM_annihilation_zmin = 30 -DM_annihilation_f_halo= 0 -DM_annihilation_z_halo= 8 - - -# 2) DM electromagnetic decay - -# 2.a) Specify the dimensionless parameter 'decay_fraction' which is -# equal to the fraction of cdm with electromagnetic decay -# products (decaying into dark radiation is handled by -# Omega_dcdm). Note: Until class 2.7, this parameter was called -# 'decay'. Its name and its meaning have slightly changed to -# avoid confusion when working with model in which the lifetime -# of the dcdm can be small (this is allowed providing that the -# 'decay_fraction' parameter is small as well). (default: set to -# 0) -DM_decay_fraction = 0. - -# 2.b) Specify the decay width of the particle 'decay_Gamma' in 1/s. -# (default: set to 0) -DM_decay_Gamma = 0. - - -# 3) PBH evaporation. In this case, check that in 5), 'f_eff_type' and -# 'f_eff' have their default values 'on_the_spot' and 1, because CLASS -# will automatically take into account the time-dependent efficiency -# of energy injection from evaporating BH, taking the spectrum of -# evaporated particles into account. - -# 3.a) Specify a dimensionless parameter 'PBH_evaporation_fraction' which is equal -# to the fraction of evaporating PBH. (default set to 0) -PBH_evaporation_fraction = 0. - -# 3.b) Specify the mass of the evaporating PBH in g. (default set to 0) -PBH_evaporation_mass = 0. - - -# 4) PBH matter accretion - -# 4.a) Specify a dimensionless parameter 'PBH_accreting_fraction' which is equal -# to the fraction of accreting PBH. (default set to 0) -PBH_accretion_fraction = 0. - -# 4.b) Specify the mass of the accreting PBH in Msun. (default set to 0) -PBH_accretion_mass = 0. - -# 4.c) Specify the 'PBH_accretion_recipe' between 'spherical_accretion' -# (computed according to Ali-Haimoud and Kamionkowski 1612.05644), or -# 'disk_accretion' (computed according to Poulin et al. 1707.04206). -# (default set to 'disk_accretion') -PBH_accretion_recipe = disk_accretion - -# 4.c.1) If you choose 'spherical_accretion', you might want to specify the -# relative velocity between PBH and baryons in km/s. -# If negative, the linear result is chosen by the code. -# (default set to -1., standard value is the linear result extrapolated to PBH.) -PBH_accretion_relative_velocities = -1. - -# 4.c.2) If you choose 'disk_accretion', you might want to specify the -# factor 'PBH_accretion_ADAF_delta' which, determines the heating -# of the electrons in the disk, influencing the emissivity. -# Can be set to 0.5 (aggressive scenario), 0.1 or 1.e-3 (conservative). -# (default set to 1.e-3) -# Furthermore you can also specify the the eigenvalue of the accretion -# rate. It rescales the perfect Bondi case. (see e.g. Ali-Haimoud -# & Kamionkowski 2016) (default set to 0.1, standard value in the ADAF -# scenario.) -PBH_accretion_ADAF_delta = 1.e-3 -PBH_accretion_eigenvalue = 0.1 - -# 5) Define the so-called injection efficiency f_eff, i.e. the factor -# determining how much of the heating is deposited at all, -# regardless of the form. There are two options to define this -# function: 'on_the_spot' or 'from_file' (default: set to 'on_the_spot'). -# -# - with 'on_the_spot', the injected energy is transformed into deposited energy -# at the same redshift with efficiency f_eff. In this case the -# user can pass explicitely the value of f_eff. (default: f_eff=1) -# -# - for 'from_file' the code reads a precomputed function in an external file -# with a path set by the user (default set to "external/heating/example_f_eff_file.dat") -f_eff_type = on_the_spot -#f_eff = -#f_eff_file = external/heating/example_f_eff_file.dat - -# 6) Define the so-called deposition function chi, i.e the function which determines -# the amount of energy effectively deposited into the different forms (heating, -# ionization, Lyman alpha and low energy). There are several options -# - by setting 'chi_type' to 'CK_2004', the approximation by Chen & Kamionkowski 2004 is employed. -# - by setting 'chi_type' to 'PF_2005', the approximation by Padmanabhan & Finkbeiner 2005 is employed. -# - by setting 'chi_type' to 'Galli_2013_file', the approximation by Galli et al. 2013 is employed. -# - by setting 'chi_type' to 'Galli_2013_analytic', the approximation by Poulin is employed. -# interpolating Galli et al. 2013 anyltically. Use this for consistency tests with -# older versions of CLASS (2.x). -# - by setting 'chi_type' to 'heat', the whole injected energy is going -# to be deposited into heat. -# - by setting 'chi_type' to 'from_x_file' or 'from_z_file', the user can -# define own deposition functions with respect to the free electron -# fraction x_e or to redshift, respectively. -# (default set to 'CK_2004') -chi_type = CK_2004 - -# 6.a) If the option 'from_file' has been chosen, define the name of the file. -# Two files 'example_chix_file.dat' and 'example_chiz_file.dat' are given -# as example in external/heating. Note that 'example_chix_file.dat' has -# been computed according to the approximations of Galli et al. 2013. -# (default set to "external/heating/example_f_eff_file.dat") -#chi_file = external/heating/example_chiz_file.dat -#chi_file = external/heating/example_chix_file.dat - - - -# ------------------------------- -# ----> Non-linear parameters: -# ------------------------------- - -# 1) If you want an estimate of the non-linear P(k) and Cls: -# Enter 'halofit' or 'Halofit' or 'HALOFIT' for Halofit -# Enter 'hmcode' or 'Hmcode' or 'HMcode' or 'HMCODE' for HMcode; -# otherwise leave blank (default: blank, linear P(k) and Cls) -non_linear = - -# 1.a) if you chose Halofit, and you have Omega0_fld != 0. (i.e. you -# set Omega_lambda=0.) & wa_fld != 0., then you might want to use the -# pk equal method of 0810.0190 and 1601.07230 by setting this flag to -# 'yes' (default: set to 'no') -pk_eq = - -# 1.b) if you chose HMcode: -# In HMcode you can specify a baryonic feedback model (otherwise only DM is used). -# Each model depends on two parameters: the minimum concentration "c_min" from the -# Bullock et al. 2001 mass-concentration relation and the halo bloating parameter "eta_0" -# introduced in Mead et al. 2015. In Mead et al. 2015 the parameters c_min and eta_0 are fitted -# to the Cosmic Emulator dark matter only simulation (Heitman et al. 2014) and the -# hydrodynamical OWLS simulations (Schaye et al. 2010, van Daalen et al. 2011). -# You can choose between the 5 models of Mead et al. 2015, Table 4: -# Model (eta_0, c_min) Explanation -# - 'emu_dmonly' (0.603, 3.13) fits the only dark matter Cosmic Emulator simulation (default) -# - 'owls_dmonly' (0.64, 3.43) fits the OWLS simulation of dark matter only -# - 'owls_ref' (0.68, 3.91) fits the OWLS simulation that includes gas cooling, heating, -# star formation and evolution, chemical enrichment and supernovae feedback -# - 'owls_agn' (0.76, 2.32) fits the OWLS simulation that includes AGN feedback -# - 'owls_dblim' (0.70, 3.01) fits the OWLS simulation that has extra supernova energy in wind velocity -# Set 'feedback model' to one of these names, -# or leave blank and pass manually the value of either 'eta_0' or 'c_min' -# (the other one will then be fixed according to equation (30) in Mead et al. 2015), -# or pass manually the two values of 'eta_0' and 'c_min' -# (default: 'feedback model' set to 'nl_emu_dmonly') -feedback model = -eta_0 = -c_min = - -# ---------------------------- -# ----> Primordial parameters: -# ---------------------------- - -# 1) Primordial spectrum type -# - 'analytic_Pk' for an analytic smooth function with amplitude, tilt, -# running, etc.; analytic spectra with feature can also be added as -# a new type; -# - 'inflation_V' for a numerical computation of the inflationary -# primordial spectrum, through a full integration of the perturbation -# equations, given a parametrization of the potential V(phi) in the -# observable window, like in astro-ph/0703625; -# - 'inflation_H' for the same, but given a parametrization of the -# potential H(phi) in the observable window, like in -# astro-ph/0710.1630; -# - 'inflation_V_end' for the same, but given a parametrization of the -# potential V(phi) in the whole region between the observable part and -# the end of inflation; -# - 'two scales' allows to specify two amplitudes instead of one -# amplitude and one tilt, like in the isocurvature mode analysis of the -# Planck inflation paper (works also for adiabatic mode only; see -# details below, item 2.c); -# - 'external_Pk' allows for the primordial spectrum to be computed -# externally by some piece of code, or to be read from a table, see -# 2.d). -# (default: set to 'analytic_Pk') -Pk_ini_type = analytic_Pk - -# 1.a) Pivot scale in Mpc-1 (default: set to 0.05) -k_pivot = 0.05 - -# 1.b) For type 'analytic_Pk': -# 1.b.1) For scalar perturbations -# curvature power spectrum value at pivot scale ('A_s' or -# 'ln_A_s_1e10') OR one of 'sigma8' or 'S8' (found by iterations using a shooting -# method). (default: set 'A_s' to 2.100549e-09) -A_s = 2.100549e-09 -#ln_A_s_1e10 = 3.04478383 -#sigma8 = 0.824398 -#S8 = 0.837868 - -# 1.b.1.1) Adiabatic perturbations: -# tilt at the same scale 'n_s', and tilt running 'alpha_s' -# (default: set 'n_s' to 0.9660499, 'alpha_s' to 0) -n_s = 0.9660499 -alpha_s = 0. - -# 1.b.1.2) Isocurvature/entropy perturbations: -# for each mode xx ('xx' being one of 'bi', 'cdi', 'nid', 'niv', -# corresponding to baryon, cdm, neutrino density and neutrino velocity -# entropy perturbations), enter the entropy-to-curvature ratio f_xx, -# tilt n_xx and running alpha_xx, all defined at the pivot scale; e.g. -# f_cdi of 0.5 means S_cdi/R equal to one half and (S_cdi/R)^2 to 0.25 -# (default: set each 'f_xx' to 1, 'n_xx' to 1, 'alpha_xx' to 0) -f_bi = 1. -n_bi = 1.5 -f_cdi=1. -f_nid=1. -n_nid=2. -alpha_nid= 0.01 -# etc. - -# 1.b.1.3) Cross-correlation between different adiabatic/entropy mode: -# for each pair (xx, yy) where 'xx' and 'yy' are one of 'ad', 'bi', -# 'cdi', 'nid', 'niv', enter the correlation c_xx_yy (parameter between -# -1 and 1, standing for cosDelta, the cosine of the cross-correlation -# angle), the tilt n_xx_yy of the function cosDelta(k), and its running -# alpha_xx_yy, all defined at the pivot scale. So, for a pair of fully -# correlated (resp. anti-correlated) modes, one should set (c_xx_yy, -# n_xx_yy, alpha_xx_yy) to (1,0,0) (resp. (-1,0,0) (default: set each -# 'c_xx_yy' to 0, 'n_xx_yy' to 0, 'alpha_xx_yy' to 0) -c_ad_bi = 0.5 -#n_ad_bi = 0.1 -c_ad_cdi = -1. -c_bi_nid = 1. -#n_bi_nid = -0.2 -#alpha_bi_nid = 0.002 -# etc. - -# 1.b.2) For tensor perturbations (if any): -# tensor-to-scalar power spectrum ratio, tilt, -# running at the pivot scale; if 'n_t' and/or 'alpha_t' is set to 'scc' -# or 'SCC' isntead of a numerical value, it will be inferred from the -# self-consistency condition of single field slow-roll inflation: for -# n_t, -r/8*(2-r/8-n_s); for alpha_t, r/8(r/8+n_s-1) (default: set 'r' -# to 1, 'n_t' to 'scc', 'alpha_t' to 'scc') -r = 1. -n_t = scc -alpha_t = scc - -# 1.c) For type 'inflation_V' -# 1.c.1) Type of potential: 'polynomial' for a Taylor expansion of the -# potential around phi_pivot. Other shapes can easily be defined in -# primordial module. -potential = polynomial - -# 1.c.2) For 'inflation_V' and 'polynomial': enter either the coefficients -# 'V_0', 'V_1', 'V_2', 'V_3', 'V_4' of the Taylor expansion (in units of -# Planck mass to appropriate power), or their ratios 'R_0', 'R_1', -# 'R_2', 'R_3', 'R_4' corresponding to (128pi/3)*V_0^3/V_1^2, -# V_1^2/V_0^2, V_2/V_0, V_1*V_3/V_0, V_1^2*V_4/V_0^3, or the -# potential-slow-roll parameters 'PSR_0', 'PSR_1', 'PSR_2', 'PSR_3', -# 'PSR_4', equal respectively to R_0, epsilon_V=R_1/(16pi), -# eta_V=R_2/(8pi), ksi_V=R_3/(8pi)^2, omega_V=R_4/(8pi)^3 (default: -# 'V_0' set to 1.25e-13, 'V_1' to 1.12e-14, 'V_2' to 6.95e-14, 'V_3' -# and 'V_4' to zero). -V_0=1.e-13 -V_1=-1.e-14 -V_2=7.e-14 -V_3= -V_4= -#R_0=2.18e-9 -#R_1=0.1 -#R_2=0.01 -#R_3= -#R_4= -#PSR_0 = 2.18e-9 -#PSR_1 = 0.001989 -#PSR_2 = 0.0003979 -#PSR_3 = -#PSR_4 = - -# 1.d) For 'inflation_H': -# enter either the coefficients 'H_0', 'H_1', 'H_2', 'H_3', 'H_4' of the -# Taylor expansion (in units of Planck mass to appropriate power), or the -# Hubble-slow-roll parameters 'HSR_0', 'HSR_1', 'HSR_2', 'HSR_3', 'HSR_4' -H_0=1.e-13 -H_1=-1.e-14 -H_2=7.e-14 -H_3= -H_4= -#HSR_0 = 2.18e-9 -#HSR_1 = 0.001989 -#HSR_2 = 0.0003979 -#HSR_3 = -#HSR_4 = - -# 1.e) For type 'inflation_V_end': -# 1.e.1) Value of the field at the minimum of the potential after inflation, or -# at a value in which you want to impose the end of inflation, in -# hybrid-like models. By convention, the code expects inflation to take -# place for values smaller than this value, with phi increasing with -# time (using a reflection symmetry, it is always possible to be in that -# case) (default: 'phi_end' set to 0) -phi_end = - -# 1.e.2) Shape of the potential. Refers to functions pre-coded in the primordail -# module, so far 'polynomial' and 'higgs_inflation'. (default: -# 'full_potential' set to 0) -full_potential = polynomial - -# 1.e.3) Parameters of the potential. The meaning of each parameter is -# explained in the function primrodial_inflation_potential() in -# source/primordial.c -Vparam0 = -Vparam1 = -Vparam2 = -Vparam3 = -Vparam4 = - -# 1.e.4) How much the scale factor a or the product (aH) increases between -# Hubble crossing for the pivot scale (during inflation) and the end of -# inflation. You can pass either: 'N_star' (standing for -# log(a_end/a_pivot)) set to a number; or 'ln_aH_ratio' (standing for -# log(aH_end/aH_pivot)) set to a number; (default: 'N_star' set to 60) -#ln_aH_ratio = 50 -#N_star = 55 - -# 1.e.5) Should the inflation module do its nomral job of numerical integration -# ('numerical') or use analytical slow-roll formulas to infer the -# primordial spectrum from the potential ('analytical')? (default: -# 'inflation_behavior' set to 'numerical') -#inflation_behavior = numerical - -# 1.f) For type 'two_scales' (currently this option works only for scalar modes, -# and either for pure adiabatic modes or adiabatic + one type of -# isocurvature): -# 1.f.1) Two wavenumbers 'k1' and 'k2' in 1/Mpc, at which primordial amplitude -# parameters will be given. The value of 'k_pivot' will not be used in -# input but quantities at k_pivot will still be calculated and stored in -# the primordial structure (no default value: compulsory input if -# 'P_k_ini type' has been set to 'two_scales') -k1=0.002 -k2=0.1 - -# 1.f.2) Two amplitudes 'P_{RR}^1', 'P_{RR}^2' for the adiabatic primordial -# spectrum (no default value: compulsory input if 'P_k_ini type' has been -# set to 'two_scales') -P_{RR}^1 = 2.3e-9 -P_{RR}^2 = 2.3e-9 - -# 1.f.3) If one isocurvature mode has been turned on ('ic' set e.g. to 'ad,cdi' -# or 'ad,nid', etc.), enter values of the isocurvature amplitude -# 'P_{II}^1', 'P_{II}^2', and cross-correlation amplitude 'P_{RI}^1', -# '|P_{RI}^2|' (see Planck paper on inflation for details on -# definitions) -P_{II}^1 = 1.e-11 -P_{II}^2 = 1.e-11 -P_{RI}^1 = -1.e-13 -|P_{RI}^2| = 1.e-13 - -# 1.f.4) Set 'special iso' to 'axion' or 'curvaton' for two particular cases: -# 'axion' means uncorrelated, n_ad equal to n_iso, 'curvaton' means fully -# anti-correlated with f_iso<0 (in the conventions of the Planck -# inflation paper this would be called fully correlated), n_iso equal -# to one; in these two cases, the last three of the four paramneters in -# 2.c.3 will be over-written give the input for 'P_{II}^1' (defaut: -# 'special_iso' left blanck, code assumes general case described by four -# parameters of 2.c.3) -special_iso = - -# 1.g) For type 'external_Pk' (see external documentation external_Pk/README.md -# for more details): -# 1.g.1) Command generating the table. If the table is already generated, just -# write "cat ". The table should have two columns (k, pk) if -# tensors are not requested, or three columns (k, pks, pkt) if they are. -#command = python external/external_Pk/generate_Pk_example.py -#command = python external/external_Pk/generate_Pk_example_w_tensors.py -command = cat external/external_Pk/Pk_example.dat -#command = cat external/external_Pk/Pk_example_w_tensors.dat - -# 1.g.2) If the table is not pregenerated, parameters to be passed to the -# command, in the right order, starting from "custom1" and up to -# "custom10". They must be real numbers. -custom1 = 0.05 # In the example command: k_pivot -custom2 = 2.215e-9 # In the example command: A_s -custom3 = 0.9624 # In the example command: n_s -custom4 = 2e-10 # In the example (with tensors) command: A_t -custom5 = -0.1 # In the example (with tensors) command: n_t -#custom6 = 0 -#custom7 = 0 -#custom8 = 0 -#custom9 = 0 -#custom10 = 0 - - - -# ------------------------- -# ----> Spectra parameters: -# ------------------------- - -# 1) Maximum l for CLs: -# - 'l_max_scalars' for CMB scalars (temperature, polarization, cmb -# lensing potential), -# - 'l_max_vectors' for CMB vectors -# - 'l_max_tensors' for CMB tensors (temperature, polarization) -# - 'l_max_lss' for Large Scale Structure Cls (density, galaxy -# lensing potential) -# Reducing 'l_max_lss' with respect to l_max_scalars reduces the execution -# time significantly (default: set 'l_max_scalars' to 2500, 'l_max_vectors' -# to 500, 'l_max_tensors' to 500, 'l_max_lss' to 300) -l_max_scalars = 2500 -#l_max_vectors = 500 -l_max_tensors = 500 -#l_max_lss = 300 - - -# 2) Parameters for the the matter density number count (option 'nCl' -# (or 'dCl')) or galaxy lensing potential (option 'sCl') Cls: -# 2.a) Enter here a description of the selection functions W(z) of each redshift -# bin; selection can be set to 'gaussian', 'tophat' or 'dirac', then pass a -# list of N mean redshifts in growing order separated by comas, 1 or N -# widths separated by comas, 1 or N bias separated by a comma, and 1 or N -# magnification bias separated by a comma. The width stands for one -# standard deviation of the gaussian (in z space), or for the half-width of -# the top-hat. Finally, non_diagonal sets the number of cross-correlation -# spectra that you want to calculate: 0 means only auto-correlation, 1 -# means only adjacent bins, and number of bins minus one means all -# correlations (default: set to 'gaussian',1,0.1,1.,0.,0) -# -# NOTE: For good performances, the code uses the Limber approximation for -# nCl. If you want high precision even with thin selection functions, -# increase the default value of the precision parameters -# l_switch_limber_for_nc_local_over_z and -# l_switch_limber_for_nc_los_over_z; for instance, add them to the -# input file with values 10000 and 2000, instead of the default 100 -# and 30. -selection=gaussian -selection_mean = 0.98,0.99,1.0,1.1,1.2 -selection_width = 0.1 -selection_bias = -selection_magnification_bias = -non_diagonal=4 - -# 2.b) It is possible to multiply the window function W(z) by a selection -# function 'dNdz' (number of objects per redshift interval). Type the name -# of the file containing the redshift in the first column and the number of -# objects in the second column (do not call it 'analytic*'). Set to -# 'analytic' to use instead the analytic expression from arXiv:1004.4640 -# (this function can be tuned in the module transfer.c, in the subroutine -# transfer_dNdz_analytic). Leave blank to use a uniform distribution -# (default). -dNdz_selection = - -# 2.c) It is possible to consider source number counts evolution. Type the name -# of the file containing the redshift on the first column and the number -# of objects on the second column (do not call it 'analytic*'). Set to -# 'analytic' to use instead the analytic expression from Eq. 48 of -# arXiv:1105.5292. Leave blank to use constant comoving number densities -# (default). -dNdz_evolution = - - -# 3) Power spectrum P(k) -# 3.a) Maximum k in P(k), 'P_k_max_h/Mpc' in units of h/Mpc or 'P_k_max_1/Mpc' -# inunits of 1/Mpc. If scalar Cls are also requested, a minimum value is -# automatically imposed (the same as in scalar Cls computation) (default: -# set to 1 1/Mpc) -P_k_max_h/Mpc = 1. -#P_k_max_1/Mpc = 0.7 - -# 3.a.1) If you want to use a different value for k_max in the primordial and -# perturbations structures, specify -# 'primordial_P_k_max_h/Mpc' in units of h/Mpc or -# 'primordial_P_k_max_1/Mpc' in units of 1/Mpc -# to define the maximum value of k for primordial power spectrum. By doing -# so, 'P_k_max_h/Mpc' will only apply to perturbations. If unspecified, -# 'primordial_P_k_max_h/Mpc' is assumed to be the same as 'P_k_max_h/Mpc'. -#primordial_P_k_max_h/Mpc = -#primordial_P_k_max_1/Mpc = - -# 3.b) Value(s) 'z_pk' of redshift(s) for P(k,z) output file(s); can be ordered -# arbitrarily, but must be separated by comas (default: set 'z_pk' to 0) -z_pk = 0 -#z_pk = 0., 1.2, 3.5 - -# 3.c) If the code is interfaced with routines that need to interpolate P(k,z) at -# various values of (k,z), enter 'z_max_pk', the maximum value of z at -# which such interpolations are needed. (default: set to maximum value in -# above 'z_pk' input) -#z_max_pk = 10. - - - -# ---------------------------------- -# ----> Lensing parameters: -# ---------------------------------- - -# 1) Relevant only if you ask for 'tCl, lCl' and/or 'pCl, lCl': if you want the -# spectrum of lensed Cls. Can be anything starting with 'y' or 'n'. -# (default: no lensed Cls) -lensing = yes - - -# 2) Should the lensing potential [phi+psi](k,tau) and the lensing spectrum Cl_phiphi be rescaled? -# You can rescale [phi+psi](k,tau) at all times by an overall amplitude and tilt: lcmb_rescale*(k/lcmb_pivot)**lcmb_tilt -# Or, more simply, you can pass the usual parameter 'A_l', and the potential will be rescaled by sqrt(A_L) -# (matches standard definition in Calabrese et al. 0803.2309) -# (default: no rescaling: A_L=lcmb_rescale=1) -A_L = -#lcmb_rescale = 1 -#lcmb_tilt = 0 -#lcmb_pivot = 0.1 - - - -# ------------------------------------- -# ----> Distortions parameters: -# ------------------------------------- - -# 1) Which kind of appriximation would you like to use for the calculation of the -# branching ratios? -# To use approximation 1) 'branching approx'=sharp_sharp -# To use approximation 2) 'branching approx'=sharp_soft -# To use approximation 3) 'branching approx'=soft_soft -# To use approximation 4) 'branching approx'=soft_soft_cons -# To use approximation 5) 'branching approx'=exact -# -# Approximation 3) violates energy conservation in the plasma, and is discouraged. -# Please be aware, that the total energy injected will NOT include the residual distortion energy. -# (default set to 'exact') -sd_branching_approx = exact - -# 1.a) If the branching ratios are = exact, the user can specify additional parameters. For any other -# branching ratio approximation, all of the following parameters are going to be ignored. -# 1.a.1) How many multipoles do you want to use for the residuals in the case of the PCA -# analysis? The value can vary between 0 and 6. (default set to 2) -sd_PCA_size = 2 - -# 1.a.2) If PCA size is different from 0, you need to specify the chosen detector, by defining -# setting "sd_detector_name" and defining any of 1.a.3.x). -# In external/distortions, the file detectors_list.dat contains a list -# of currently "known" detectors, i.e. detectors for which the PCA decomposition -# has already been computed. If no detector name is specified, but the detector specifics -# 1.a.3.x) are, the name will be created automatically. If no name and no specifics are -# given, PIXIE values are going to be assumed. -# -# For instance, in the case of "sd_detector_name=PIXIE", the values are fixed respectively to 30 GHz, -# 1005 GHz, 15 GHz and 5 10^-26 W/(m^2 Hz sr), and all spectral shapes and branching ratios are -# already precumputed. -# -# It would be very helpful if, once computed the vectors for a new detector, the user would -# send us the files containing spectral shapes and branching ratios (see e.g. -# external/distortions for templates). -sd_detector_name = PIXIE - -# 1.a.3) Provide the specifics of the detector (frequencies and sensitivities) -# Either define a path to a full noise file or enter the specifics here -# 1.a.3.1) Give a path to the full noise file containing -# - the frequency array in GHz and -# - the detector noise in 10^-26 W/(m^2 Hz sr) for each frequency -# Please supply the path relative to external/distortions -#sd_detector_file = FIRAS_nu_delta_I.dat - -# 1.a.3.2) If you did not supply the full noise file, you need to set -# - the minumum frequency in GHz -# - the maximum frequency in GHz -# - the bin width in GHz or alternatively the number of bins -# - the detector noise in 10^-26 W/(m^2 Hz sr) -# of the chosen detector. -#sd_detector_nu_min = 30. -#sd_detector_nu_max = 1000. -#sd_detector_nu_delta = 15. -#sd_detector_bin_number = 65 -#sd_detector_delta_Ic = 5. - - -# 2) Only calculate non-LCDM contributions to heating? -# Sometimes, for comparison, one might want to disable all LCDM contributions to SDs. -# Can be set to anything starting with 'y' or 'n' (default: no) -sd_only_exotic = no - - -# 3) Include g distortions? -# Can be set to anything starting with 'y' or 'n' (default: no) -sd_include_g_distortion = no - - -# 4) If you want to manually add a y and/or a mu parameter on top of the calculated values, specify -# 'sd_add_y' or 'sd_add_mu' or both (default set to 0 for both) -sd_add_y = 0. -sd_add_mu = 0. - - -# 5) Include SZ effect from reionization? Can be set to anything starting with 'y' or 'n' -# (default: no) -include_SZ_effect = no - -# 5.a) Specify the type of approximation you want to use for the SZ effect -# - by setting 'sd_reio_type' to 'Nozawa_2005', the approximation by Nozawa et al. 2005 is employed. -# - by setting 'sd_reio_type' to 'Chluba_2012', the approximation by Chluba et al. 2012 is employed. -# Note that, for the moment, this appoximation is only valid for cluster temperatures lower -# than few KeV. -# (default set to 'Chluba_2012') -#sd_reio_type = Chluba_2012 - - - -# ---------------------------------- -# ----> Output parameters: -# ---------------------------------- - -# 1) Output for external files -# 1.a) File name root 'root' for all output files (if Cl requested, written to -# '_cl.dat'; if P(k) requested, written to '_pk.dat'; plus -# similar files for scalars, tensors, pairs of initial conditions, etc.; -# if file with input parameters requested, written to -# '_parameters.ini') -# If no root is specified, the root will be set to 'output/' -# (default: output/) -#root = output/test - -# 1.a.1) If root is specified, do you want to keep overwriting the file, -# or do you want to create files numbered as 'N_'. -# Can be set to anything starting with 'y' or 'n' (default: no) -overwrite_root = no - -# 1.b) Do you want headers at the beginning of each output file (giving -# precisions on the output units/ format) ? Can be set to anything -# starting with 'y' or 'n' (default: yes) -headers = yes - -# 1.c) In all output files, do you want columns to be normalized and ordered -# with the default CLASS definitions or with the CAMB definitions (often -# idential to the CMBFAST one) ? Set 'format' to either 'class', 'CLASS', -# 'camb' or 'CAMB' (default: 'class') -format = class - -# 1.d) Do you want to write a table of background quantitites in a file? This -# will include H, densities, Omegas, various cosmological distances, sound -# horizon, etc., as a function of conformal time, proper time, scale -# factor. Can be set to anything starting with 'y' or 'no' (default: no) -write_background = no - -# 1.e) Do you want to write a table of thermodynamics quantitites in a file? -# Can be set to anything starting with 'y' or 'n'. (default: no) -write_thermodynamics = no - -# 1.f) Do you want to write a table of perturbations to files for certain -# wavenumbers k? Dimension of k is 1/Mpc. The actual wave numbers are -# chosen such that they are as close as possible to the requested k-values. (default: none) -#k_output_values = 0.01, 0.1, 0.0001 - -# 1.g) Do you want to write the primordial scalar(/tensor) spectrum in a file, -# with columns k [1/Mpc], P_s(k) [dimensionless], ( P_t(k) -# [dimensionless])? Can be set to anything starting with 'y' or 'n'. (default: no) -write_primordial = no - -# 1.h) Do you want to write the exotic energy injection function in a file, -# with columns z [dimensionless], dE/dz_inj, dE/dz_dep [J/(m^3 s)]? -# 1.i) Do you want to write also the non-injected photon heating? -# File created if 'write_exotic_injection' or -# 'write_noninjection' set to something containing the letter -# 'y' or 'Y', file written, otherwise not written (default: no) -write_exotic_injection = no -#write_noninjection = no - -# 1.k) Do you want to write the spectral distortions in a file, -# with columns x [dimensionless], DI(x) [dimensionless]? -# File created if 'write_distortions' set to something containing the letter -# 'y' or 'Y', file written, otherwise not written (default: no) -write_distortions = no - -# 1.l) Do you want to have all input/precision parameters which have been read -# written in file 'parameters.ini', and those not written in file -# 'unused_parameters' ? Can be set to anything starting with 'y' -# or 'n'. (default: yes) -write_parameters = yes - -# 1.m) Do you want a warning written in the standard output when an input -# parameter or value could not be interpreted ? Can be set to anything starting -# with 'y' or 'n' (default: no) -write_warnings = no - -# 2) Amount of information sent to standard output: Increase integer values -# to make each module more talkative (default: all set to 0) -input_verbose = 1 -background_verbose = 1 -thermodynamics_verbose = 1 -perturbations_verbose = 1 -transfer_verbose = 1 -primordial_verbose = 1 -harmonic_verbose = 1 -fourier_verbose = 1 -lensing_verbose = 1 -distortions_verbose = 1 -output_verbose = 1 diff --git a/include/background.h b/include/background.h index 809c12601..90aea38c1 100644 --- a/include/background.h +++ b/include/background.h @@ -8,6 +8,7 @@ #include "growTable.h" #include "arrays.h" #include "dei_rkck.h" +#include "evolver_rkdp45.h" #include "parser.h" /** list of possible types of spatial curvature */ @@ -18,6 +19,13 @@ enum spatial_curvature {flat,open,closed}; enum equation_of_state {CLP,EDE}; +/** Nature of NEDE fluid */ +enum NEDE_fld_nature +{ + NEDE_fld_A, + NEDE_fld_B, + NEDE_fld_BIII +}; /** list of possible parametrizations of the varying fundamental constants */ @@ -81,6 +89,41 @@ struct background double Omega_ini_dcdm; /**< \f$ \Omega_{ini,dcdm} \f$: rescaled initial value for dcdm density (see 1407.2418 for definitions) */ double Gamma_dcdm; /**< \f$ \Gamma_{dcdm} \f$: decay constant for decaying cold dark matter */ double tau_dcdm; + + /* New Early Dark Energy quantities */ + double Omega_NEDE; /* NEDE density parameter before decay */ + double Omega0_NEDE; /* NEDE density parameter today */ + double f_NEDE; /* Fraction of NEDE at decay time */ + double Omega_trigger_decay; /* NEDE trigger at decay time */ + + short Junction_tag; + double Bubble_trigger_H_over_m; /* Decay time trigger */ + double NEDE_trigger_mass; /* Trigger field mass */ + double NEDE_trigger_ini; /* Trigger initial field value */ + double Omega0_trigger; /* Omega trigger field today */ + double phi_ini_trigger; + double phi_prime_ini_trigger; + double three_eos_NEDE; /* NEDE e.o.s. (scenario A) */ + short decay_flag; /* NEDE decay flag; True iff NEDE has decayed */ + + + double trigger_fluid_H_over_m; /* NEDE trigger fluid approximation threshold */ + int trigger_fluid_approximation; /* True iff trigger fluid approximation is on */ + /* Quantities when trigger FA is turned on */ + double H_fluid; + double H_prime_fluid; + double a_trigger_fluid; + double a_trigger_fluid_safe; + double trigger_fluid_safety_factor; + + + /* NEDE decay time */ + double tau_decay; + double a_decay; + double z_decay_NEDE; + /* NEDE fluid nature*/ + int NEDE_fld_nature; + int N_ncdm; /**< Number of distinguishable ncdm species */ /* the following parameters help to define tabulated ncdm p-s-d passed in file */ @@ -177,6 +220,21 @@ struct background int index_bg_rho_dcdm; /**< dcdm density */ int index_bg_rho_dr; /**< dr density */ + int index_bg_rho_NEDE; /**< NEDE density */ + int index_bg_w_NEDE; /**< NEDE eos parameter */ + + /* NEDE trigger field quantities*/ + int index_bg_phi_trigger; /**< trigger field value */ + int index_bg_phi_prime_trigger; /**< trigger field derivative wrt conformal time */ + int index_bg_V_trigger; /**< trigger field potential V */ + int index_bg_dV_trigger; /**< trigger field potential derivative V' */ + int index_bg_ddV_trigger; /**< trigger field potential second derivative V'' */ + int index_bg_rho_trigger; /**< trigger field energy density */ + int index_bg_p_trigger; /**< trigger field pressure */ + int index_bg_p_prime_trigger; /**< scalar field pressure */ + int index_bg_w_trigger; + int index_bg_ca2_trigger; + int index_bg_phi_scf; /**< scalar field value */ int index_bg_phi_prime_scf; /**< scalar field derivative wrt conformal time */ int index_bg_V_scf; /**< scalar field potential V */ @@ -261,6 +319,10 @@ struct background int index_bi_rho_fld; /**< {B} fluid density */ int index_bi_phi_scf; /**< {B} scalar field value */ int index_bi_phi_prime_scf; /**< {B} scalar field derivative wrt conformal time */ + + int index_bi_phi_trigger; /**< {B} NEDE trigger scalar field value */ + int index_bi_phi_prime_trigger; /**< {B} NEDE trigger scalar field derivative wrt conformal time */ + int index_bi_rho_trigger; /**< {B} NEDE trigger energy density */ int index_bi_time; /**< {C} proper (cosmological) time in Mpc */ int index_bi_rs; /**< {C} sound horizon */ @@ -295,6 +357,11 @@ struct background short has_idr; /**< presence of interacting dark radiation? */ short has_curvature; /**< presence of global spatial curvature? */ short has_varconst; /**< presence of varying fundamental constants? */ + + short has_NEDE; /**< presence of NEDE? */ + short has_NEDE_pert; /**< presence of NEDE perturbations? */ + short has_NEDE_trigger; /**< presence of NEDE trigger? */ + short has_NEDE_trigger_DM; /**< tracking trigger density? */ //@} @@ -423,6 +490,26 @@ extern "C" { double * dw_over_da_fld, double * integral_fld); + int background_quantities_NEDE( + struct background *pba, + double a, + double a_prime_over_a, + double *rho, + double *p, + double *w, + double *dw_over_da, + double *ca2); + + int background_quantities_NEDE_trigger( + struct background *pba, + double a, + double a_prime_over_a, + double H, + double H_prime, + double *w, + double *dw_over_da, + double *ca2); + int background_varconst_of_z( struct background* pba, double z, @@ -565,6 +652,23 @@ extern "C" { double phi ); + + /** Trigger field potential and its derivatives **/ + double V_trigger( + struct background *pba, + double phi + ); + + double dV_trigger( + struct background *pba, + double phi + ); + + double ddV_trigger( + struct background *pba, + double phi + ); + /** Coupling between scalar field and matter **/ double Q_scf( struct background *pba, diff --git a/include/common.h b/include/common.h index 36165e128..58f693fe2 100644 --- a/include/common.h +++ b/include/common.h @@ -24,6 +24,7 @@ #define _SUCCESS_ 0 /**< integer returned after successful call of a function */ #define _FAILURE_ 1 /**< integer returned after failure in a function */ +#define _APPROXIMATION_REACHED_ 2 /**< integer returned after reaching the threshold of a background approximation */ #define _ERRORMSGSIZE_ 2048 /**< generic error messages are cut beyond this number of characters */ typedef char ErrorMsg[_ERRORMSGSIZE_]; /**< Generic error messages (there is such a field in each structure) */ @@ -128,6 +129,18 @@ int string_begins_with(char* thestring, char beginchar); #define class_call(function, error_message_from_function, error_message_output) \ class_call_except(function, error_message_from_function,error_message_output,) +/* macro for calling output in evolvers with possiblity for approximation reached */ +#define class_evolver_output(function, error_message_from_function, error_message_output) { \ + int output_return = function; \ + if (output_return == _FAILURE_) { \ + class_call_message(error_message, output, error_message) \ + return _FAILURE_; \ + } \ + else if (output_return == _APPROXIMATION_REACHED_) { \ + done = _TRUE_; \ + } \ +} + /* same in parallel region */ #define class_call_parallel(function, error_message_from_function, error_message_output) { \ if (abort == _FALSE_) { \ @@ -347,7 +360,8 @@ struct output; */ enum evolver_type { rk, /* Runge-Kutta integrator */ - ndf15 /* stiff integrator */ + ndf15, /* stiff integrator */ + rkdp45 /* Runge-Kutta Dormand-Prince */ }; /** diff --git a/include/evolver_rkdp45.h b/include/evolver_rkdp45.h new file mode 100755 index 000000000..e2724c7c5 --- /dev/null +++ b/include/evolver_rkdp45.h @@ -0,0 +1,43 @@ +#ifndef __RK__ +#define __RK__ +#include "common.h" +/**************************************************************/ + +/** + * Boilerplate for C++ + */ +#ifdef __cplusplus +extern "C" { +#endif + +int evolver_rkdp45( + int (*derivs)(double x,double * y,double * dy, + void * parameters_and_workspace, ErrorMsg error_message), + double t_ini, + double t_final, + double * y_inout, + int* used_in_output, + int neq, + void * parameters_and_workspace_for_derivs, + double rtol, + double minimum_variation, + int (*timescale_and_approximation)(double x, + void * parameters_and_workspace, + double * timescales, + ErrorMsg error_message), + double timestep_over_timescale, + double* t_vec, + int tres, + int (*output)(double x,double y[],double dy[],int index_x,void * parameters_and_workspace, + ErrorMsg error_message), + int (*print_variables)(double x, double y[], double dy[], void *parameters_and_workspace, + ErrorMsg error_message), + ErrorMsg error_message); + +#ifdef __cplusplus +} +#endif + +/**************************************************************/ + +#endif diff --git a/include/input.h b/include/input.h index 8b78e3335..c3adf7741 100644 --- a/include/input.h +++ b/include/input.h @@ -203,9 +203,9 @@ * For shooting method: definition of the possible targets */ -enum target_names {theta_s, theta_s_100, Omega_dcdmdr, omega_dcdmdr, Omega_scf, Omega_ini_dcdm, omega_ini_dcdm, sigma8, S8}; +enum target_names {theta_s, theta_s_100, Omega_dcdmdr, omega_dcdmdr, Omega_scf, Omega_ini_dcdm, omega_ini_dcdm, z_decay_NEDE, Omega0_NEDE_trigger_DM, NEDE_trigger_ini, sigma8, S8}; /* Important: Keep this number equal to the number of target_names (except sigma8, S8), and keep sigma8, S8 at the very end */ -#define _NUM_TARGETS_ 7 +#define _NUM_TARGETS_ 10 /* Important: add one for each new target_names */ enum computation_stage {cs_background, cs_thermodynamics, cs_perturbations, cs_primordial, cs_nonlinear, cs_transfer, cs_spectra}; diff --git a/include/parser.h b/include/parser.h index 1214231a0..c869aa00d 100644 --- a/include/parser.h +++ b/include/parser.h @@ -100,6 +100,19 @@ extern "C" { int N_options, int* valid); + int parser_extend(struct file_content * pfc, + int N_extend, + ErrorMsg errmsg); + + int parser_copy(struct file_content * pfc_source, + struct file_content * pfc_destination, + int index_start, + int index_end); + + int parser_init_from_pfc(struct file_content * pfc_source, + struct file_content * pfc_destination, + ErrorMsg errmsg); + #ifdef __cplusplus } #endif diff --git a/include/perturbations.h b/include/perturbations.h index 7747919d9..6019ae75d 100644 --- a/include/perturbations.h +++ b/include/perturbations.h @@ -31,6 +31,19 @@ enum rsa_idr_flags {rsa_idr_off, rsa_idr_on}; enum ufa_flags {ufa_off, ufa_on}; enum ncdmfa_flags {ncdmfa_off, ncdmfa_on}; +/* New EDE, before decay CCa_on, corresponding to no perts.*/ +enum CCa_flags {CCa_on, CCa_off}; + +/*New EDE, we stop tracking NewEDE pert when sda_on*/ +enum sda_flags {sda_off, sda_on}; + +/*New EDE, we apply trigger fluid approximation when tfa_on*/ +enum tfa_flags {tfa_off, tfa_on}; +enum tavg_flags {tavg_off, tavg_on}; + +/* Nature of NEDE fluid, either effective rest-frame sound speed is tracking the adiabatic sound speed (adiabatic case) or it is constant. */ +enum NEDE_ceff_nature {NEDE_ceff_const, NEDE_ceff_tracking, NEDE_ceff_twice_linear}; + //@} /** @@ -169,6 +182,16 @@ struct perturbations double three_ceff2_ur;/**< 3 x effective squared sound speed for the ultrarelativistic perturbations */ double three_cvis2_ur;/**< 3 x effective viscosity parameter for the ultrarelativistic perturbations */ + + double three_ceff2_NEDE; + double three_cvis2_NEDE; + double cs2_NEDE; + int NEDE_ceff_nature; + // Parameters of the piecewise linear sound speed + double NEDE_cs2_slope_1; + double NEDE_cs2_intercept_1; + double NEDE_cs2_slope_2; + double NEDE_cs2_intercept_2; double z_max_pk; /**< when we compute only the matter spectrum / transfer functions, but not the CMB, we are sometimes interested to sample source functions at very high redshift, way before recombination. This z_max_pk will then fix the initial sampling time of the sources. */ @@ -176,6 +199,8 @@ struct perturbations double * beta_idr; /**< Angular contribution to collisional term at l>=2 for idr-idr */ int idr_nature; /**< Nature of the interacting dark radiation (free streaming or fluid) */ + + int plot_gauge; /** Gauge to plot the perturbations in */ //@} @@ -245,6 +270,8 @@ struct perturbations short has_source_delta_dr; /**< do we need source for delta of decay radiation? */ short has_source_delta_ur; /**< do we need source for delta of ultra-relativistic neutrinos/relics? */ short has_source_delta_ncdm; /**< do we need source for delta of all non-cold dark matter species (e.g. massive neutrinos)? */ + short has_source_delta_NEDE; /**< do we need source for delta of NEDE? */ + short has_source_delta_trigger; /**< do we need source for delta from trigger field? */ short has_source_theta_m; /**< do we need source for theta of total matter? */ short has_source_theta_cb; /**< do we ALSO need source for theta of ONLY cdm and baryon? */ short has_source_theta_tot; /**< do we need source for theta total? */ @@ -259,6 +286,8 @@ struct perturbations short has_source_theta_dr; /**< do we need source for theta of ultra-relativistic neutrinos/relics? */ short has_source_theta_ur; /**< do we need source for theta of ultra-relativistic neutrinos/relics? */ short has_source_theta_ncdm; /**< do we need source for theta of all non-cold dark matter species (e.g. massive neutrinos)? */ + short has_source_theta_NEDE; /**< do we need source for theta of NEDE? */ + short has_source_theta_trigger; /**< do we need source for theta of trigger field? */ short has_source_phi; /**< do we need source for metric fluctuation phi? */ short has_source_phi_prime; /**< do we need source for metric fluctuation phi'? */ short has_source_phi_plus_psi; /**< do we need source for metric fluctuation (phi+psi)? */ @@ -293,6 +322,8 @@ struct perturbations int index_tp_delta_ur; /**< index value for delta of ultra-relativistic neutrinos/relics */ int index_tp_delta_idr; /**< index value for delta of interacting dark radiation */ int index_tp_delta_ncdm1; /**< index value for delta of first non-cold dark matter species (e.g. massive neutrinos) */ + int index_tp_delta_NEDE; /**< index value for delta of NEDE */ + int index_tp_delta_trigger; /**< index value for delta of trigger field */ int index_tp_perturbed_recombination_delta_temp; /**< Gas temperature perturbation */ int index_tp_perturbed_recombination_delta_chi; /**< Inionization fraction perturbation */ @@ -310,6 +341,8 @@ struct perturbations int index_tp_theta_idm; /**< index value for theta of interacting dark matter */ int index_tp_theta_dr; /**< index value for F1 of decay radiation */ int index_tp_theta_ncdm1; /**< index value for theta of first non-cold dark matter species (e.g. massive neutrinos) */ + int index_tp_theta_NEDE; /**< index value for theta of NEDE */ + int index_tp_theta_trigger; /**< index value for theta of trigger field */ int index_tp_phi; /**< index value for metric fluctuation phi */ int index_tp_phi_prime; /**< index value for metric fluctuation phi' */ @@ -474,6 +507,14 @@ struct perturbations_vector int index_pt_Gamma_fld; /**< unique dark energy dynamical variable in PPF case */ int index_pt_phi_scf; /**< scalar field density */ int index_pt_phi_prime_scf; /**< scalar field velocity */ + int index_pt_phi_trigger; /**< trigger field density */ + int index_pt_phi_prime_trigger; /**< trigger field velocity */ + int index_pt_delta_trigger_fld; + int index_pt_theta_trigger_fld; + int index_pt_delta_trigger_cycle_integral; + int index_pt_theta_hat_trigger_cycle_integral; + int index_pt_delta_t_trigger_cycle_integral; + int index_pt_theta_hat_t_trigger_cycle_integral; int index_pt_delta_ur; /**< density of ultra-relativistic neutrinos/relics */ int index_pt_theta_ur; /**< velocity of ultra-relativistic neutrinos/relics */ int index_pt_shear_ur; /**< shear of ultra-relativistic neutrinos/relics */ @@ -484,6 +525,12 @@ struct perturbations_vector int index_pt_shear_idr; /**< shear of interacting dark radiation */ int index_pt_l3_idr; /**< l=3 of interacting dark radiation */ int l_max_idr; /**< max momentum in Boltzmann hierarchy (at least 3) for interacting dark radiation */ + + int index_pt_delta_NEDE; + int index_pt_theta_NEDE; + int index_pt_shear_NEDE; + int index_pt_delta_trigger; + int index_pt_rho_plus_p_theta_trigger; /* perturbed recombination */ int index_pt_perturbed_recombination_delta_temp; /**< Gas temperature perturbation */ @@ -627,6 +674,10 @@ struct perturbations_workspace int index_ap_rsa_idr; /**< index for dark radiation streaming approximation */ int index_ap_ufa; /**< index for ur fluid approximation */ int index_ap_ncdmfa; /**< index for ncdm fluid approximation */ + int index_ap_CCa; /**< index for New EDE approximation*/ + int index_ap_sda; /**< index for New EDE approximation*/ + int index_ap_tfa; /**< index for New EDE approximation*/ + int index_ap_tavg; /**< index for New EDE approximation*/ int ap_size; /**< number of relevant approximations for a given mode */ int * approx; /**< array of approximation flags holding at a given time: approx[index_ap] */ @@ -967,6 +1018,14 @@ extern "C" { ErrorMsg error_message ); +int trigger_NEDE_cs2( + struct background *pba, + double a, + double k, + double H, + double *cs2 + ); + #ifdef __cplusplus } #endif diff --git a/include/precisions.h b/include/precisions.h index b9bd961b5..d9f12ffa4 100644 --- a/include/precisions.h +++ b/include/precisions.h @@ -14,9 +14,10 @@ class_precision_parameter(a_ini_over_a_today_default,double,1.e-14) */ class_precision_parameter(background_Nloga,int,40000) /** - * Evolver to be used for thermodynamics (rk, ndf15) + * Evolver to be used for thermodynamics (rk, ndf15, rkdp45) */ -class_type_parameter(background_evolver,int,enum evolver_type,ndf15) +// class_type_parameter(background_evolver,int,enum evolver_type,rkdp45) +class_precision_parameter(background_evolver,int,1) /** * Tolerance of the background integration, giving the allowed relative integration error. * (used by both evolvers) @@ -386,7 +387,8 @@ class_precision_parameter(neglect_CMB_sources_below_visibility,double,1.0e-3) /** * The type of evolver to use: options are ndf15 or rk */ -class_type_parameter(evolver,int,enum evolver_type,ndf15) +//class_type_parameter(evolver,int,enum evolver_type,rkdp45) +class_precision_parameter(evolver,int,1) /* * Primordial parameters @@ -596,6 +598,10 @@ class_precision_parameter(tol_sd_detector,double,1.e-5) class_string_parameter(sd_external_path,"/external/distortions","sd_external_path") +/* + NEDE precision settings + */ +class_precision_parameter(sub_dom_cond,double,0) #undef class_precision_parameter #undef class_string_parameter diff --git a/include/thermodynamics.h b/include/thermodynamics.h index f02f25910..1fbe4465e 100644 --- a/include/thermodynamics.h +++ b/include/thermodynamics.h @@ -5,6 +5,7 @@ #include "background.h" #include "evolver_ndf15.h" +#include "evolver_rkdp45.h" #include "evolver_rkck.h" #include "wrap_hyrec.h" #include "wrap_recfast.h" diff --git a/include/transfer.h b/include/transfer.h index f243432aa..dbe018214 100644 --- a/include/transfer.h +++ b/include/transfer.h @@ -5,8 +5,6 @@ #include "fourier.h" #include "hyperspherical.h" -#include -#include #include "errno.h" /* macro: test if index_tt is in the range between index and index+num, while the flag is true */ diff --git a/montepython_tree/input/runNEDE_canonical.param b/montepython_tree/input/runNEDE_canonical.param new file mode 100644 index 000000000..8bf25f735 --- /dev/null +++ b/montepython_tree/input/runNEDE_canonical.param @@ -0,0 +1,162 @@ +#------Experiments to test (separated with commas)----- +data.experiments=['Planck_highl_TTTEEE','Planck_lowl_TT','Planck_lowl_EE','Planck_lensing','bao_fs_boss_dr12','bao_smallz_2014','H0_local','Pantheon','He'] + + +#------ Settings for the over-sampling. +# The first element will always be set to 1, for it is the sampling of the +# cosmological parameters. The other numbers describe the over sampling of the +# nuisance parameter space. This array must have the same dimension as the +# number of blocks in your run (so, 1 for cosmological parameters, and then 1 +# for each experiment with varying nuisance parameters). +# Note that when using Planck likelihoods, you definitely want to use [1, 4], +# to oversample as much as possible the 14 nuisance parameters. +# Remember to order manually the experiments from slowest to fastest (putting +# Planck as the first set of experiments should be a safe bet, except if you +# also have LSS experiments). +# If you have experiments without nuisance, you do not need to specify an +# additional entry in the over_sampling list (notice for instance that, out of +# the three Planck likelihoods used, only Planck_highl requires nuisance +# parameters, therefore over_sampling has a length of two (cosmology, plus one +# set of nuisance). +data.over_sampling=[1, 5,2] + +#------ Parameter list ------- + +# data.parameters[class name] = [mean, min, max, 1-sigma, scale, role] +# - if min max irrelevant, put to None +# - if fixed, put 1-sigma to 0 +# - if scale irrelevant, put to 1, otherwise to the appropriate factor +# - role is either 'cosmo', 'nuisance' or 'derived'. You should put the derived +# parameters at the end, and in case you are using the `-j fast` Cholesky +# decomposition, you should order your nuisance parameters from slowest to +# fastest. + +# Cosmological parameters list + +data.parameters['omega_b'] = [ 2.28, None, None, 0.028, 0.01, 'cosmo'] +data.parameters['omega_cdm'] = [0.133, None, None, 0.0027, 1, 'cosmo'] +data.parameters['h'] = [.715, None, None, .006, 1, 'cosmo'] +data.parameters['ln10^{10}A_s'] = [ 3.077, None, None, 0.0029, 1, 'cosmo'] +data.parameters['n_s'] = [0.99, None, None, 0.0074, 1, 'cosmo'] +data.parameters['tau_reio'] = [0.057, 0.04, None, 0.013, 1, 'cosmo'] +#NEDE parameters +data.parameters['f_NEDE'] = [0.14, 0.0000001, 0.3, 0.014, 1, 'cosmo'] +data.parameters['log10z'] = [3.3, 2, 4, 0.08, 1, 'cosmo'] +data.parameters['three_eos_NEDE'] = [2, 1, 3, 0.08, 1, 'cosmo'] + +# Nuisance parameter list, same call, except the name does not have to be a class name +data.parameters['A_cib_217'] = [ 47.2, 0, 200, 6.2593, 1, 'nuisance'] +data.parameters['cib_index'] = [ -1.3, -1.3, -1.3, 0, 1, 'nuisance'] +data.parameters['xi_sz_cib'] = [ 0.42, 0, 1, 0.33, 1, 'nuisance'] +data.parameters['A_sz'] = [ 7.23, 0, 10, 1.4689, 1, 'nuisance'] +data.parameters['ps_A_100_100'] = [ 251.0, 0, 400, 29.438, 1, 'nuisance'] +data.parameters['ps_A_143_143'] = [ 47.4, 0, 400, 9.9484, 1, 'nuisance'] +data.parameters['ps_A_143_217'] = [ 47.3, 0, 400, 11.356, 1, 'nuisance'] +data.parameters['ps_A_217_217'] = [ 119.8, 0, 400, 10.256, 1, 'nuisance'] +data.parameters['ksz_norm'] = [ 0.01, 0, 10, 2.7468, 1, 'nuisance'] +data.parameters['gal545_A_100'] = [ 8.86, 0, 50, 1.8928, 1, 'nuisance'] +data.parameters['gal545_A_143'] = [ 11.10, 0, 50, 1.8663, 1, 'nuisance'] +data.parameters['gal545_A_143_217'] = [ 19.8, 0, 100, 3.8796, 1, 'nuisance'] +data.parameters['gal545_A_217'] = [ 95.1, 0, 400, 6.9759, 1, 'nuisance'] +data.parameters['galf_EE_A_100'] = [ 0.055, 0.055, 0.055, 0, 1, 'nuisance'] +data.parameters['galf_EE_A_100_143'] = [ 0.040, 0.040, 0.040, 0, 1, 'nuisance'] +data.parameters['galf_EE_A_100_217'] = [ 0.094, 0.094, 0.094, 0, 1, 'nuisance'] +data.parameters['galf_EE_A_143'] = [ 0.086, 0.086, 0.086, 0, 1, 'nuisance'] +data.parameters['galf_EE_A_143_217'] = [ 0.21, 0.21, 0.21, 0, 1, 'nuisance'] +data.parameters['galf_EE_A_217'] = [ 0.70, 0.70, 0.70, 0, 1, 'nuisance'] +data.parameters['galf_EE_index'] = [ -2.4, -2.4, -2.4, 0, 1, 'nuisance'] +data.parameters['galf_TE_A_100'] = [ 0.114, 0, 10, 0.038762, 1, 'nuisance'] +data.parameters['galf_TE_A_100_143'] = [ 0.134, 0, 10, 0.030096, 1, 'nuisance'] +data.parameters['galf_TE_A_100_217'] = [ 0.482, 0, 10, 0.086185, 1, 'nuisance'] +data.parameters['galf_TE_A_143'] = [ 0.224, 0, 10, 0.055126, 1, 'nuisance'] +data.parameters['galf_TE_A_143_217'] = [ 0.664, 0, 10, 0.082349, 1, 'nuisance'] +data.parameters['galf_TE_A_217'] = [ 2.08, 0, 10, 0.27175, 1, 'nuisance'] +data.parameters['galf_TE_index'] = [ -2.4, -2.4, -2.4, 0, 1, 'nuisance'] +data.parameters['calib_100T'] = [ 999.69, 0, 3000, 0.61251, 0.001, 'nuisance'] +data.parameters['calib_217T'] = [ 998.16, 0, 3000, 0.63584, 0.001, 'nuisance'] +data.parameters['calib_100P'] = [ 1.021, 1.021, 1.021, 0, 1, 'nuisance'] +data.parameters['calib_143P'] = [ 0.966, 0.966, 0.966, 0, 1, 'nuisance'] +data.parameters['calib_217P'] = [ 1.040, 1.040, 1.040, 0, 1, 'nuisance'] +data.parameters['A_cnoise_e2e_100_100_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_cnoise_e2e_143_143_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_cnoise_e2e_217_217_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_100_100_TT'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_143_143_TT'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_143_217_TT'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_217_217_TT'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_100_100_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_100_143_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_100_217_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_143_143_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_143_217_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_sbpx_217_217_EE'] = [ 1, 1, 1, 0, 1, 'nuisance'] +data.parameters['A_planck'] = [ 1.00061, 0.9, 1.1, 0.0025, 1, 'nuisance'] +data.parameters['A_pol'] = [ 1, 1, 1, 0, 1, 'nuisance'] + + +data.parameters['M'] = [-19.1, None, None, 0.004, 1,'nuisance'] + +# Derived parameters + +data.parameters['YHe'] = [1, None, None, 0, 1, 'derived'] +#data.parameters['H0'] = [0, None, None, 0, 1, 'derived'] +#data.parameters['A_s'] = [0, None, None, 0, 1e-9, 'derived'] +data.parameters['sigma8'] = [0, None, None, 0, 1, 'derived'] +data.parameters['rs_d'] = [0, None, None, 0, 1, 'derived'] +data.parameters['z_decay'] = [0, None, None, 0, 1, 'derived'] +data.parameters['NEDE_trigger_mass'] = [0, None, None, 0, 1, 'derived'] + +# Other cosmo parameters (fixed parameters, precision parameters, etc.) + +data.cosmo_arguments['sBBN file'] = data.path['cosmo']+'/bbn/sBBN_2017.dat' +data.cosmo_arguments['k_pivot'] = 0.05 + + +# The base model features two massless +# and one massive neutrino with m=0.06eV. +# The settings below ensures that Neff=3.046 +# and m/omega = 93.14 eV + +data.cosmo_arguments['N_ur'] = 2.0328 +data.cosmo_arguments['N_ncdm'] = 1 +data.cosmo_arguments['m_ncdm'] = 0.06 +data.cosmo_arguments['T_ncdm'] = 0.71611 + + + +# These two are required to get sigma8 as a derived parameter +# (class must compute the P(k) until sufficient k) +data.cosmo_arguments['output'] = 'mPk' +data.cosmo_arguments['P_k_max_h/Mpc'] = 1. + + +data.cosmo_arguments['H_over_m_NEDE']=0.2 +data.cosmo_arguments['NEDE_trigger_ini'] = 0.0001 +data.cosmo_arguments['Junction_tag'] = 1 +data.cosmo_arguments['three_cvis2_NEDE'] = 0 +data.cosmo_arguments['NEDE_ceff_nature']='tracking' + +# Recommended precision settings; less strict settings are probably also OK +data.cosmo_arguments['back_integration_stepsize'] = 1.e-3 +data.cosmo_arguments['tol_background_integration'] = 1e-10 +data.cosmo_arguments['tol_perturbations_integration'] = 1e-8 +data.cosmo_arguments['perturbations_integration_stepsize'] = 0.5 +data.cosmo_arguments['perturbations_sampling_stepsize'] = 0.003 +data.cosmo_arguments['tol_shooting_deltax_rel'] = 1e-8 +data.cosmo_arguments['tol_shooting_deltax'] = 1e-8 +data.cosmo_arguments['tol_shooting_deltaF'] = 1e-8 +data.cosmo_arguments['background_evolver'] = 1 +data.cosmo_arguments['evolver'] = 1 + +data.cosmo_arguments['background_verbose'] = 4 +data.cosmo_arguments['perturbations_verbose'] = 2 + +#makes sure that all modes start before the transition of EDE, i.e. before z=30k. +data.cosmo_arguments['start_large_k_at_tau_h_over_tau_k'] = 0.000001 +data.cosmo_arguments['start_small_k_at_tau_c_over_tau_h'] = 0.000001 + +#------ Mcmc parameters ---- + +data.N=10 +data.write_step=5 + diff --git a/montepython_tree/montepython/data.py b/montepython_tree/montepython/data.py new file mode 100644 index 000000000..3d81bf96e --- /dev/null +++ b/montepython_tree/montepython/data.py @@ -0,0 +1,1149 @@ +""" +.. module:: data + :synopsis: Define the Data and Parameter classes + +.. moduleauthor:: Benjamin Audren +""" +from __future__ import print_function +import os +import sys +import math +import random as rd +import warnings +import subprocess as sp +import re + +import io_mp # Needs to talk to io_mp.py file for the logging + # of parameters +from io_mp import dictitems,dictvalues,dictkeys +import prior +from scipy.optimize import fsolve + +# A modified version of Python dictionary in order to keep track of the order +# in it (much the same as in an array). In case an older version of Python is +# used, this module does not belong to collections. Please remind to put that +# into your PYTHONPATH variable. +try: + from collections import OrderedDict as od +except ImportError: + try: + from ordereddict import OrderedDict as od + except ImportError: + raise io_mp.MissingLibraryError( + "If you are running with Python v2.5 or 2.6, you need" + + "to manually install the ordereddict package by placing" + + "the file ordereddict.py in your Python Path") + + +class Data(object): + """ + Store all relevant data to communicate between the different modules. + + """ + + def __init__(self, command_line, path): + """ + The Data class holds the cosmological information, the parameters from + the MCMC run, the information coming from the likelihoods. It is a wide + collections of information, with in particular two main dictionaries: + cosmo_arguments and mcmc_parameters. + + It defines several useful **methods**. The following ones are called + just once, at initialization: + + * :func:`fill_mcmc_parameters` + * :func:`read_file` + * :func:`read_version` + * :func:`group_parameters_in_blocks` + + On the other hand, these two following functions are called every step. + + * :func:`check_for_slow_step` + * :func:`update_cosmo_arguments` + + Finally, the convenient method :func:`get_mcmc_parameters` will be + called in many places, to return the proper list of desired parameters. + + It has a number of different **attributes**, and the more important + ones are listed here: + + * :attr:`boundary_loglike` + * :attr:`cosmo_arguments` + * :attr:`mcmc_parameters` + * :attr:`need_cosmo_update` + * :attr:`log_flag` + + .. note:: + + The `experiments` attribute is extracted from the parameter file, + and contains the list of likelihoods to use + + .. note:: + + The path argument will be used in case it is a first run, and hence + a new folder is created. If starting from an existing folder, this + dictionary will be compared with the one extracted from the + log.param, and will use the latter while warning the user. + + .. warning:: + + New in version 2.0.0, you can now specify an oversampling of the + nuisance parameters, to hasten the execution of a run with + likelihoods that have many of them. You should specify a new field + in the parameter file, `data.over_sampling = [1, ...]`, that + contains a 1 on the first element, and then the over sampling of + the desired likelihoods. This array must have the same size as the + number of blocks (1 for the cosmo + 1 for each likelihood with + varying nuisance parameters). You need to call the code with the + flag `-j jast` for it to be used. + + To create an instance of this class, one must feed the following + parameters and keyword arguments: + + Parameters + ---------- + command_line : NameSpace + NameSpace containing the input from the :mod:`parser_mp`. It + stores the input parameter file, the jumping methods, the output + folder, etc... Most of the information extracted from the + command_file will be transformed into :class:`Data` attributes, + whenever it felt meaningful to do so. + path : dict + Contains a dictionary of important local paths. It is used here to + find the cosmological module location. + + """ + + # Initialisation of the random seed + rd.seed() + + # Store the parameter file + self.param = command_line.param + + # Recover jumping method from command_line + self.jumping = command_line.jumping + self.jumping_factor = command_line.jumping_factor + + # Store the rest of the command line + self.command_line = command_line + + # Initialise the path dictionnary. + self.path = {} + + self.boundary_loglike = -1e30 + """ + Define the boundary loglike, the value used to defined a loglike + that is out of bounds. If a point in the parameter space is affected to + this value, it will be automatically rejected, hence increasing the + multiplicity of the last accepted point. + """ + + # Creation of the two main dictionnaries: + self.cosmo_arguments = {} + """ + Simple dictionary that will serve as a communication interface with the + cosmological code. It contains all the parameters for the code that + will not be set to their default values. It is updated from + :attr:`mcmc_parameters`. + + :rtype: dict + """ + self.mcmc_parameters = od() + """ + Ordered dictionary of dictionaries, it contains everything needed by + the :mod:`mcmc` module for the MCMC procedure. Every parameter name + will be the key of a dictionary, containing the initial configuration, + role, status, last accepted point and current point. + + :rtype: ordereddict + """ + + # Arguments for PyMultiNest + self.NS_param_names = [] + self.NS_arguments = {} + """ + Dictionary containing the parameters needed by the PyMultiNest sampler. + It is filled just before the run of the sampler. Those parameters not + defined will be set to the default value of PyMultiNest. + + :rtype: dict + """ + + # Arguments for PyPolyChord + self.PC_param_names = [] + self.PC_arguments = {} + """ + Dictionary containing the parameters needed by the PyPolyChord sampler. + It is filled just before the run of the sampler. Those parameters not + defined will be set to the default value of PyPolyChord. + + :rtype: dict + """ + + # Initialise the experiments attribute + self.experiments = [] + + # Initialise the oversampling setting + self.over_sampling = [] + """ + List storing the respective over sampling of the parameters. The first + entry, applied to the cosmological parameters, will always be 1. + Setting it to anything else would simply rescale the whole process. If + not specified otherwise in the parameter file, all other numbers will + be set to 1 as well. + + :rtype: list + """ + + # Default value for the number of steps + self.N = 10 + + # Create the variable out, and out_name, which will be initialised + # later by the :mod:`io_mp` module + self.out = None + self.out_name = '' + + # If the parameter file is not a log.param, the path will be read + # before reading the parameter file. + if self.param.find('log.param') == -1: + self.path.update(path) + + # Read from the parameter file to fill properly the mcmc_parameters + # dictionary. + self.fill_mcmc_parameters() + + # Test if the recovered path agrees with the one extracted from + # the configuration file. + if self.path != {}: + if not 'root' in self.path: + self.path.update({'root': path['root']}) + if self.path != path: + warnings.warn( + "Your code location in the log.param file is " + "in contradiction with your .conf file. " + "I will use the one from log.param.") + + # Determine which cosmological code is in use + if os.path.isfile(self.path['cosmo']+'/main/class.c'): + self.cosmological_module_name = 'CLASS' + else: + self.cosmological_module_name = None + + # check for MPI + try: + from mpi4py import MPI + comm = MPI.COMM_WORLD + rank = comm.Get_rank() + except ImportError: + # set all chains to master if no MPI + rank = 0 + + # Recover the cosmological code version (and git hash if relevant). + # To implement a new cosmological code, please add another case to the + # test below. + if self.cosmological_module_name == 'CLASS': + # Official version number + common_file_path = os.path.join( + self.path['cosmo'], 'include', 'common.h') + with open(common_file_path, 'r') as common_file: + for line in common_file: + if line.find('_VERSION_') != -1: + self.version = line.split()[-1].replace('"', '') + break + if not command_line.silent and not rank: + print('with CLASS %s' % self.version) + # Git version number and branch + try: + # This nul_file helps to get read of a potential useless error + # message + with open(os.devnull, "w") as nul_file: + self.git_version = sp.Popen( + ["git", "rev-parse", "HEAD"], + cwd=self.path['cosmo'], + stdout=sp.PIPE, + stderr=nul_file).communicate()[0].strip() + self.git_branch = sp.Popen( + ["git", "rev-parse", "--abbrev-ref", "HEAD"], + cwd=self.path['cosmo'], + stdout=sp.PIPE, + stderr=nul_file).communicate()[0].strip() + except (sp.CalledProcessError, OSError): + # Note, OSError seems to be raised on some systems, instead of + # sp.CalledProcessError - which seems to be linked to the + # existence of os.devnull, so now both error are caught. + warnings.warn( + "Running CLASS from a non version-controlled repository") + self.git_version, self.git_branch = '', '' + + # If using an existing log.param, read in and compare this number + # to the already stored one + if self.param.find('log.param') != -1: + try: + version, git_version, git_branch = self.read_version( + self.param_file) + if version != self.version: + warnings.warn( + "Your version of CLASS: %s" % self.version + + " does not match the one used previously" + + " in this folder (%s)." % version + + " Proceed with caution") + else: + if self.git_branch != git_branch: + warnings.warn( + "CLASS set to branch %s" % self.git_branch + + ", wrt. the one used in the log.param:" + + " %s." % git_branch) + if self.git_version != git_version: + warnings.warn( + "CLASS set to version %s" % self.git_version + + ", wrt. the one used in the log.param:" + + " %s." % git_version) + + except AttributeError: + # This error is raised when the regular expression match + # failed - due to comparing to an old log.param that did + # not have this feature properly implemented. Ignore this. + pass + + else: + raise io_mp.CosmologicalModuleError( + "Could not find any of the registered cosmological modules, such as {CLASS}." + " The code tried to search for "+self.path['cosmo']+'/main/class.c'+" but the file did not exist." + " If you want to check for another cosmological module version" + " please add an elif clause to this part of the code.") + + # End of initialisation with the parameter file + self.param_file.close() + + self.log_flag = False + """ + Stores the information whether or not the likelihood data files need to + be written down in the log.param file. Initially at False. + + :rtype: bool + """ + + self.need_cosmo_update = True + """ + `added in version 1.1.1`. It stores the truth value of whether the + cosmological block of parameters was changed from one step to another. + See :meth:`group_parameters_in_blocks` + + :rtype: bool + """ + + # logging the parameter file (only if folder does not exist !) + ## temporary variable for readability + log_param = os.path.join(command_line.folder, 'log.param') + + if (os.path.exists(command_line.folder) and + not os.path.exists(log_param)): + if command_line.param is not None: + warnings.warn( + "Detecting empty folder, logging the parameter file") + io_mp.log_parameters(self, command_line) + self.log_flag = True + if not os.path.exists(command_line.folder): + os.makedirs(command_line.folder) + # Logging of parameters + io_mp.log_parameters(self, command_line) + self.log_flag = True + + if not command_line.silent and not rank: + sys.stdout.write('\nTesting likelihoods for:\n ->') + print(', '.join(self.experiments)+'\n') + + self.initialise_likelihoods(self.experiments) + + # Storing parameters by blocks of speed + self.group_parameters_in_blocks() + + # Finally, log the cosmo_arguments used. This comes in the end, because + # it can be modified inside the likelihoods init functions + if self.log_flag: + io_mp.log_cosmo_arguments(self, command_line) + io_mp.log_default_configuration(self, command_line) + + # Log plotting parameter names file for compatibility with GetDist + io_mp.log_parameter_names(self, command_line) + + def fill_mcmc_parameters(self): + """ + Initializes the ordered dictionary :attr:`mcmc_parameters` from + the input parameter file. + + It uses :meth:`read_file`, and initializes instances of + :class:`parameter` to actually fill in :attr:`mcmc_parameters`. + + """ + + # Define temporary quantities, only to simplify the input in the + # parameter file + self.parameters = od() + + # Read from the parameter file everything + try: + self.param_file = open(self.param, 'r') + except IOError: + raise io_mp.ConfigurationError( + "Error in initializing the Data class, the parameter file " + + "{0} does not point to a proper file".format(self.param)) + # In case the parameter file is a log.param, scan first once the file + # to extract only the path dictionnary. + if self.param.find('log.param') != -1: + self.read_file(self.param, 'data', field='path') + self.read_file(self.param, 'data') + + # Test here whether the number of parameters extracted correspond to + # the number of lines (to make sure no doublon is present) + number_of_parameters = sum( + [1 for l in open(self.param, 'r') if l and l.find('#') == -1 + and l.find('data.parameters[') != -1]) + if number_of_parameters != len(self.parameters): + raise io_mp.ConfigurationError( + "You probably have two lines in your parameter files with " + "the same parameter name. This is most probably an error, " + "which will cause problems down the line. Please fix this.") + + # Do the same for every experiments - but only if you are starting a + # new folder. Otherwise, this step will actually be done when + # initializing the likelihood. + if self.param.find('log.param') == -1: + for experiment in self.experiments: + self.read_file(self.param, experiment, separate=True) + + # Finally create all the instances of the Parameter given the input. + for key, value in dictitems(self.parameters): + self.mcmc_parameters[key] = Parameter(value, key) + + # When there is no prior edge requested, the syntax consists in setting it to 'None' in the input file. + # There is also an old syntax which is deprecated: '-1'. + # We still allow for that, but just after parsing it, we substitute it with 'None'. + # When the user really wants a prior edge in -1, he can write -1.0, then the next lines will not substitute it. + for i in [1,2]: + if (str(self.mcmc_parameters[key]['initial'][i]) == '-1'): + self.mcmc_parameters[key]['initial'][i] = None + + """ + Transform from parameters dictionary to mcmc_parameters dictionary of + instances from the class :class:`parameter` (inheriting from dict) + """ + + def initialise_likelihoods(self, experiments): + """ + Given an array of experiments, return an ordered dict of instances + + .. Note:: + + in the __init__ method, experiments is naturally self.experiments, + but it is useful to keep it as a parameter, for the case of + importance sampling. + + """ + + self.lkl = od() + # adding the likelihood directory to the path, to import the module + # then, for each library, calling an instance of the likelihood. + # Beware, though, if you add new likelihoods, they should go to the + # folder likelihoods/yourlike/yourlike.py, and contain a yourlike.data, + # otherwise the following set of commands will not work anymore. + + # For the logging if log_flag is True, each likelihood will log its + # parameters + + # Due to problems in relative import, this line must be there. Until a + # better solution is found. It adds the root folder of the MontePython + # used as the first element in the sys.path + sys.path.insert(0, self.path['root']) + + for elem in experiments: + folder = os.path.abspath(os.path.join( + self.path['MontePython'], "likelihoods", "%s" % elem)) + # add the folder of the likelihood to the path of libraries to... + # ... import easily the likelihood.py program + try: + exec("from likelihoods.%s import %s" % ( + elem, elem)) + except ImportError as message: + raise io_mp.ConfigurationError( + "Trying to import the %s likelihood" % elem + + " as asked in the parameter file, and failed." + " Please make sure it is in the `montepython/" + "likelihoods` folder, and is a proper python " + "module. Check also that the name of the class" + " defined in the __init__.py matches the name " + "of the folder. In case this is not enough, " + "here is the original message: %s\n" % message) + # Initialize the likelihoods. Depending on the values of + # command_line and log_flag, the routine will call slightly + # different things. If log_flag is True, the log.param will be + # appended. + try: + exec("self.lkl['%s'] = %s('%s/%s.data',\ + self, self.command_line)" % ( + elem, elem, folder, elem)) + except KeyError as e: + if e.find('clik') != -1: + raise io_mp.ConfigurationError( + "You should provide a 'clik' entry in the dictionary " + "path defined in the file default.conf") + else: + raise io_mp.ConfigurationError( + "The following key: '%s' was not found" % e) + + def read_file(self, param, structure, field='', separate=False): + """ + Execute all lines concerning the Data class from a parameter file + + All lines starting with `data.` will be replaced by `self.`, so the + current instance of the class will contain all the information. + + .. note:: + + A rstrip() was added at the end, because of an incomprehensible bug + on some systems that imagined some inexistent characters at the end + of the line... Now should work + + .. note:: + + A security should be added to protect from obvious attacks. + + Parameters + ---------- + param : str + Name of the parameter file + structure : str + Name of the class entries we want to execute (mainly, data, or any + other likelihood) + + Keyword Arguments + ----------------- + field : str + If nothing is specified, this routine will execute all the lines + corresponding to the `structure` parameters. If you specify a + specific field, like `path`, only this field will be read and + executed. + separate : bool + If this flag is set to True, a container class will be created for + the structure field, so instead of appending to the namespace of + the data instance, it will append to a sub-namespace named in the + same way that the desired structure. This is used to extract custom + values from the likelihoods, allowing to specify values for the + likelihood directly in the parameter file. + + """ + if separate: + exec("self.%s = Container()" % structure) + with open(param, 'r') as param_file: + for line in param_file: + if line.find('#') == -1 and line: + lhs = line.split('=')[0] + if lhs.find(structure+'.') != -1: + if field: + # If field is not an empty string, you want to skip + # the execution of the line (exec statement) if you + # do not find the exact searched field + if lhs.find('.'.join([structure, field])) == -1: + continue + if not separate: + exec(line.replace(structure+'.', 'self.').rstrip()) + else: + exec(line.replace( + structure+'.', 'self.'+structure+'.').rstrip()) + + def group_parameters_in_blocks(self): + """ + Regroup mcmc parameters by blocks of same speed + + This method divides all varying parameters from :attr:`mcmc_parameters` + into as many categories as there are likelihoods, plus one (the slow + block of cosmological parameters). + + It creates the attribute :attr:`block_parameters`, to be used in the + module :mod:`mcmc`. + + .. note:: + + It does not compute by any mean the real speed of each parameter, + instead, every parameter belonging to the same likelihood will + be considered as fast as its neighbour. + + .. warning:: + + It assumes that the nuisance parameters are already written + sequentially, and grouped together (not necessarily in the order + described in :attr:`experiments`). If you mix up the different + nuisance parameters in the .param file, this routine will not + method as intended. It also assumes that the cosmological + parameters are written at the beginning of the file. + + """ + array = [] + # First obvious block is all cosmological parameters + array.append(len(self.get_mcmc_parameters(['varying', 'cosmo']))) + # Then, store all nuisance parameters + nuisance = self.get_mcmc_parameters(['varying', 'nuisance']) + + # Create an array to keep track of the already taken into account + # nuisance parameters. This will come in handy when using likelihoods + # that share some nuisance parameters. + used_nuisance = [] + for likelihood in dictvalues(self.lkl): + count = 0 + for elem in nuisance: + if elem in likelihood.nuisance: + if elem not in used_nuisance: + count += 1 + used_nuisance.append(elem) + likelihood.varying_nuisance_parameters = count + + # Then circle through them + index = 0 + while index < len(nuisance): + elem = nuisance[index] + flag = False + # For each one, check if they belong to a likelihood + for likelihood in dictvalues(self.lkl): + if (elem in likelihood.nuisance) and (index < len(nuisance)): + # If yes, store the number of nuisance parameters needed + # for this likelihood. + flag = True + array.append( + likelihood.varying_nuisance_parameters+array[-1]) + index += likelihood.varying_nuisance_parameters + continue + if not flag: + # If the loop reaches this part, it means this nuisance + # parameter was associated with no likelihood: this should not + # happen + raise io_mp.ConfigurationError( + "nuisance parameter %s " % elem + + "is associated to no likelihood") + # Store the result + self.block_parameters = array + + # Setting a default value for the over_sampling array + if not self.over_sampling: + self.over_sampling = [1 for _ in range(len(self.block_parameters))] + # Test that the over_sampling list has the same size as + # block_parameters. + else: + try: + assert len(self.block_parameters) == len(self.over_sampling) + except AssertionError: + raise io_mp.ConfigurationError( + "The length of the over_sampling field should be" + " equal to the number of blocks (one for cosmological " + "parameters, plus one for each likelihood with " + "nuisance parameters)") + + # Create a list of indices corresponding of the oversampling strategy + self.assign_over_sampling_indices() + + def assign_over_sampling_indices(self): + """ + Create the list of varied parameters given the oversampling + """ + self.over_sampling_indices = [] + for index in range(len(self.get_mcmc_parameters(['varying']))): + if index == 0: + self.over_sampling_indices.append(index) + else: + block_index = self.block_parameters.index( + [i for i in self.block_parameters if index < i][0]) + for _ in range(self.over_sampling[block_index]): + self.over_sampling_indices.append(index) + + def read_version(self, param_file): + """ + Extract version and subversion from an existing log.param + """ + # Read the first line (cosmological code version) + first_line = param_file.readline() + param_file.seek(0) + regexp = re.match( + ".*\(branch: (.*), hash: (.*)\).*", + first_line) + version = first_line.split()[1] + git_branch, git_version = regexp.groups() + return version, git_version, git_branch + + def get_mcmc_parameters(self, table_of_strings): + """ + Returns an ordered array of parameter names filtered by + `table_of_strings`. + + Parameters + ---------- + table_of_strings : list + List of strings whose role and status must be matched by a + parameter. For instance, + + >>> data.get_mcmc_parameters(['varying']) + ['omega_b', 'h', 'amplitude', 'other'] + + will return a list of all the varying parameters, both + cosmological and nuisance ones (derived parameters being `fixed`, + they wont be part of this list). Instead, + + >>> data.get_mcmc_parameters(['nuisance', 'varying']) + ['amplitude', 'other'] + + will only return the nuisance parameters that are being varied. + + """ + table = [] + for key, value in dictitems(self.mcmc_parameters): + number = 0 + for subvalue in dictvalues(value): + for string in table_of_strings: + if subvalue == string: + number += 1 + if number == len(table_of_strings): + table.append(key) + return table + + def check_for_slow_step(self, new_step): + """ + Check whether the value of cosmological parameters were + changed, and if no, skip computation of the cosmology. + + """ + parameter_names = self.get_mcmc_parameters(['varying']) + cosmo_names = self.get_mcmc_parameters(['cosmo']) + + need_change = 0 + + # For all elements in the varying parameters: + for elem in parameter_names: + i = parameter_names.index(elem) + # If it is a cosmological parameter + if elem in cosmo_names: + if self.mcmc_parameters[elem]['current'] != new_step[i]: + need_change += 1 + + # If any cosmological value was changed, + if need_change > 0: + self.need_cosmo_update = True + else: + self.need_cosmo_update = False + + for likelihood in dictvalues(self.lkl): + # If the cosmology changed, you need to recompute the likelihood + # anyway + if self.need_cosmo_update: + likelihood.need_update = True + continue + # Otherwise, check if the nuisance parameters of this likelihood + # were changed + need_change = 0 + for elem in parameter_names: + i = parameter_names.index(elem) + if elem in likelihood.nuisance: + if self.mcmc_parameters[elem]['current'] != new_step[i]: + need_change += 1 + if need_change > 0: + likelihood.need_update = True + else: + likelihood.need_update = False + + def update_cosmo_arguments(self): + """ + Put in :attr:`cosmo_arguments` the current values of + :attr:`mcmc_parameters` + + This method is called at every step in the Markov chain, to update the + dictionary. In the Markov chain, the scale is not remembered, so one + has to apply it before giving it to the cosmological code. + + .. note:: + + When you want to define new parameters in the Markov chain that do + not have a one to one correspondance to a cosmological name, you + can redefine its behaviour here. You will find in the source + several such examples. + + .. note:: + + For complex CLASS parameters, that expect a string of numbers + separated with commas, you can now use the name of the argument, + for instance :code:`m_ncdm`, then append a double underscore and a + number. So if you run with two cosmological parameters, + :code:`m_ncdm__1` and :code:`m_ncdm__2`, this function will + automatically concatenate the two and feed class :code:`m_ncdm`. + You still have to make sure that the other variables are properly + set, like :code:`N_ncdm` to 2, in this example. + + """ + # For all elements in any cosmological parameters + for elem in self.get_mcmc_parameters(['cosmo']): + # Fill in the dictionnary with the current value of parameters + self.cosmo_arguments[elem] = \ + self.mcmc_parameters[elem]['current'] *\ + self.mcmc_parameters[elem]['scale'] + + # For all elements in the cosmological parameters from the mcmc list, + # translate any-one that is not directly a CLASS parameter into one. + # The try: except: syntax ensures that the first call + for elem in self.get_mcmc_parameters(['cosmo']): + # infer h from Omega_Lambda and delete Omega_Lambda + if elem == 'Omega_Lambda': + omega_b = self.cosmo_arguments['omega_b'] + omega_cdm = self.cosmo_arguments['omega_cdm'] + Omega_Lambda = self.cosmo_arguments['Omega_Lambda'] + self.cosmo_arguments['h'] = math.sqrt( + (omega_b+omega_cdm) / (1.-Omega_Lambda)) + del self.cosmo_arguments[elem] + # infer omega_cdm from Omega_L and delete Omega_L + elif elem == 'Omega_L': + omega_b = self.cosmo_arguments['omega_b'] + h = self.cosmo_arguments['h'] + Omega_L = self.cosmo_arguments['Omega_L'] + self.cosmo_arguments['omega_cdm'] = (1.-Omega_L)*h*h-omega_b + del self.cosmo_arguments[elem] + # infer omega_cdm from omega_m (assuming one standard massive neutrino and omega_nu=m_nu/93.14) and delete omega_m + elif elem == 'omega_m': + omega_b = self.cosmo_arguments['omega_b'] + omega_m = self.cosmo_arguments['omega_m'] + try: + omega_nu = self.cosmo_arguments['m_ncdm'] / 93.14 + except: + omega_nu = 0. + self.cosmo_arguments['omega_cdm'] = omega_m - omega_b - omega_nu + del self.cosmo_arguments[elem] + + elif elem == 'log10z': + self.cosmo_arguments['z_decay_NEDE'] = 10**self.cosmo_arguments[elem] + del self.cosmo_arguments[elem] + + elif elem == 'ln10^{10}A_s': + self.cosmo_arguments['A_s'] = math.exp( + self.cosmo_arguments[elem]) / 1.e10 + del self.cosmo_arguments[elem] + + elif elem == 'exp_m_2_tau_As': + tau_reio = self.cosmo_arguments['tau_reio'] + self.cosmo_arguments['A_s'] = self.cosmo_arguments[elem] * \ + math.exp(2.*tau_reio) + del self.cosmo_arguments[elem] + elif elem == 'f_cdi': + self.cosmo_arguments['n_cdi'] = self.cosmo_arguments['n_s'] + elif elem == 'beta': + self.cosmo_arguments['alpha'] = 2.*self.cosmo_arguments['beta'] + elif elem == 'M_tot_NH' or elem == '{\sum}m_nu_NH': + # By T. Brinckmann + # Normal hierarchy massive neutrinos. Calculates the individual + # neutrino masses from M_tot_NH and deletes M_tot_NH + if not self.cosmo_arguments['N_ncdm'] == 3: + raise ValueError( + "N_ncdm is not equal to 3." + " This value should be exactly 3.") + # From Esteban et al. 2016: https://arxiv.org/abs/1611.01514 + delta_m_squared_atm=2.524e-3 #2.45e-3 + delta_m_squared_sol=7.50e-5 #7.50e-5 + #m1_func = lambda m1, M_tot, d_m_sq_atm, d_m_sq_sol: M_tot**2. + 0.5*d_m_sq_sol - d_m_sq_atm + m1**2. - 2.*M_tot*m1 - 2.*M_tot*(d_m_sq_sol+m1**2.)**0.5 + 2.*m1*(d_m_sq_sol+m1**2.)**0.5 + m1_func = lambda m1, M_tot, d_m_sq_atm, d_m_sq_sol: M_tot - m1 - (d_m_sq_sol + m1**2.)**0.5 - (d_m_sq_atm + m1**2.)**0.5 + m1,opt_output,success,output_message = fsolve(m1_func,self.cosmo_arguments[elem]/3.,(self.cosmo_arguments[elem],delta_m_squared_atm,delta_m_squared_sol),full_output=True) + if not success == 1: + raise ValueError( + "Failed to estimate m1. Reason: "+output_message+ + " Exiting run.") + m1 = m1[0] + m2 = (delta_m_squared_sol + m1**2.)**0.5 + #m3 = (delta_m_squared_atm + 0.5*(m2**2. + m1**2.))**0.5 + m3 = (delta_m_squared_atm + m1**2.)**0.5 + if m1+m2+m3 > self.cosmo_arguments[elem]+0.001*self.cosmo_arguments[elem]: + raise ValueError( + "Failed to estimate m1 resulting in sum(m_i) > M_tot." + " Exiting run.") + self.cosmo_arguments['m_ncdm'] = r'%g, %g, %g' % (m1,m2,m3) + del self.cosmo_arguments[elem] + elif elem == 'M_tot_IH'or elem == '{\sum}m_nu_IH': + # By T. Brinckmann + # Inverted hierarchy massive neutrinos. Calculates the individual + # neutrino masses from M_tot_IH and deletes M_tot_IH + if not self.cosmo_arguments['N_ncdm'] == 3: + raise ValueError( + "N_ncdm is not equal to 3." + " This value should be exactly 3.") + # From Esteban et al. 2016: https://arxiv.org/abs/1611.01514 + delta_m_squared_atm=-2.514e-3 #-2.45e-3 + delta_m_squared_sol=7.50e-5 #7.50e-5 + #m1_func = lambda m1, M_tot, d_m_sq_atm, d_m_sq_sol: M_tot**2. + 0.5*d_m_sq_sol - d_m_sq_atm + m1**2. - 2.*M_tot*m1 - 2.*M_tot*(d_m_sq_sol+m1**2.)**0.5 + 2.*m1*(d_m_sq_sol+m1**2.)**0.5 + m1_func = lambda m1, M_tot, d_m_sq_atm, d_m_sq_sol: M_tot - m1 - (d_m_sq_sol + m1**2.)**0.5 - (abs(d_m_sq_atm + d_m_sq_sol + m1**2.))**0.5 + m1,opt_output,success,output_message = fsolve(m1_func,self.cosmo_arguments[elem]/2.,(self.cosmo_arguments[elem],delta_m_squared_atm,delta_m_squared_sol),full_output=True) + if not success == 1: + raise ValueError( + "Failed to estimate m1. Reason: "+output_message+ + " Exiting run.") + m1 = m1[0] + m2 = (delta_m_squared_sol + m1**2.)**0.5 + #m3 = (delta_m_squared_atm + 0.5*(m2**2. + m1**2.))**0.5 + m3 = (delta_m_squared_atm + m2**2.)**0.5 + if m1+m2+m3 > self.cosmo_arguments[elem]+0.001*self.cosmo_arguments[elem]: + raise ValueError( + "Failed to estimate m1 resulting in sum(m_i) > M_tot." + "Exiting run.") + if delta_m_squared_atm + delta_m_squared_sol + m1**2. < 0.: + raise ValueError( + "Failed to correctly estimate m1. Found m1^2 = %f < %f," + "but m1^2 should always be greater than this value." % (m1**2.,- delta_m_squared_sol - delta_m_squared_atm)) + self.cosmo_arguments['m_ncdm'] = r'%g, %g, %g' % (m1,m2,m3) + del self.cosmo_arguments[elem] + elif elem == 'M_tot' or elem == '{\sum}m_nu': + # By T. Brinckmann + # Massive neutrinos with identical non-zero mass. Calculates the + # individual neutrino masses from M_tot and deletes M_tot + if not self.cosmo_arguments['N_ncdm'] == 1: + raise ValueError( + "N_ncdm is not equal to 1." + " This value should be exactly 1.") + self.cosmo_arguments['m_ncdm'] = self.cosmo_arguments[elem]/self.cosmo_arguments['deg_ncdm'] + del self.cosmo_arguments[elem] + elif elem == 'm_s_eff': + # By T. Brinckmann + # conversion from effective sterile neutrino mass to physical sterile neutrino mass, assuming that this + # is the ncdm species number 2 and that it is Dodelson-Widrow like (i.e same temperature as active neutrinos) + #print self.cosmo_arguments + #self.cosmo_arguments['m_ncdm__2'] = self.cosmo_arguments['deg_ncdm__2']*self.cosmo_arguments[elem] + m_s_eff = self.cosmo_arguments[elem]/self.cosmo_arguments['deg_ncdm__2'] + self.cosmo_arguments['m_ncdm'] = r'%g, %g' % (float(self.cosmo_arguments['m_ncdm']), m_s_eff) + del self.cosmo_arguments[elem] + elif elem == 'log10N_dg': + self.cosmo_arguments['N_dg'] = 10**(self.cosmo_arguments[elem]) + del self.cosmo_arguments[elem] + elif elem == 'log10fn': + self.cosmo_arguments['f_nadm'] = 10**(self.cosmo_arguments[elem]) + del self.cosmo_arguments[elem] + elif elem == 'log10Gamma': + self.cosmo_arguments['invtau0_nadm_dg'] = 10**(self.cosmo_arguments[elem]) + del self.cosmo_arguments[elem] + elif elem == 'w0wa': + self.cosmo_arguments['wa_fld'] = self.cosmo_arguments[elem] - self.cosmo_arguments['w0_fld'] + del self.cosmo_arguments[elem] + + # Finally, deal with all the parameters ending with __i, where i is + # an integer. Replace them all with their name without the trailing + # double underscore, concatenated with each other. The test is + # always on the one ending with __1, as it will be the first on the + # list, and deal with all the others. + elif re.search(r'__1', elem): + original_name = re.search(r'(.*)__1', elem).groups()[0] + # Recover the values of all the other elements + values = [self.cosmo_arguments[elem]] + for other_elem in self.get_mcmc_parameters(['cosmo']): + match = re.search(r'%s__([2-9])' % original_name, + other_elem) + if match: + values.append(self.cosmo_arguments[other_elem]) + # create the cosmo_argument + self.cosmo_arguments[original_name] = ', '.join( + ['%g' % value for value in values]) + # Delete the now obsolete entries of the dictionary + for index in range(1, len(values)+1): + del self.cosmo_arguments[ + original_name + '__%i' % index] + @staticmethod + def folder_is_initialised(folder): + """ + Static method to call for checking if a folder was already initialised + + This method can be used to speed up the mpi initialisation in + :mod:`run`. If a process finds that the folder is already a proper + Monte Python one, it sends directly a 'go' signal to its next in line. + + .. warning:: + + This method assumes that the last lines of the log.param are the + path indication. If this would ever change, adjust this method + accordingly. + + """ + # If the folder is not there, easy answer: False! + if not os.path.isdir(folder): + return False + # Recover the log.param from the folder, and assert it exists + log_param_path = os.path.join(folder, 'log.param') + if not os.path.isfile(log_param_path): + return False + # Quickly load it to a string, and assert that the path has been + # written (which are the last lines) + with open(log_param_path, 'r') as log_param: + text = log_param.readlines() + if text[-1].find('path[') != -1: + return True + else: + return False + + def __cmp__(self, other): + """ + Redefinition of the 'compare' method for two instances of this class. + + It will decide which basic operations to perform when the code asked if + two instances are the same (in case you want to launch a new chain in + an existing folder, with your own parameter file) Comparing + cosmological code versions (warning only, will not fail the comparison) + + """ + if self.version != other.version: + warnings.warn( + "You are running with a different version of your " + + "cosmological code") + + # Defines unordered version of the dictionaries of parameters + self.uo_parameters = {} + other.uo_parameters = {} + + # Check if all the experiments are tested again, + if len(list(set(other.experiments).symmetric_difference( + set(self.experiments)))) == 0: + # Check that they have been called with the same .data file, stored + # in dictionary when initializing. + for experiment in self.experiments: + for elem in self.lkl[experiment].dictionary: + if self.lkl[experiment].dictionary[elem] != \ + other.lkl[experiment].dictionary[elem]: + sys.stdout.write('in your parameter file: ') + print(self.lkl[experiment].dictionary) + sys.stdout.write('in log.param: ') + print(other.lkl[experiment].dictionary) + return -1 + # Fill in the unordered version of dictionaries + for key, elem in dictitems(self.mcmc_parameters): + self.uo_parameters[key] = elem['initial'] + for key, elem in dictitems(other.mcmc_parameters): + other.uo_parameters[key] = elem['initial'] + + # And finally compare them (standard comparison between + # dictionnaries, will return True if both have the same keys and + # values associated to them. + return cmp(self.uo_parameters, other.uo_parameters) + else: + return -1 + + def __call__(self, ctx): + """ + Interface layer with CosmoHammer + + Store quantities to a the context, to be accessed by the Cosmo Module + and each of the likelihoods. + + Parameters + ---------- + ctx : context + Contains several dictionaries storing data and cosmological + information + + """ + # Recover the cosmological parameter value from the context + parameters = ctx.getParams() + + # Storing them as current points + for index, elem in enumerate(self.get_mcmc_parameters(["varying"])): + self.mcmc_parameters[elem]['current'] = parameters[index] + + # Propagating this to the cosmo_arguments dictionary + self.update_cosmo_arguments() + + # Store itself into the context + ctx.add('data', self) + + +class Parameter(dict): + """ + Store all important fields, and define a few convenience methods + + """ + def __init__(self, array, key): + """ + This class replaces the old function defined in the Data class, called + `from_input_to_mcmc_parameters`. The traduction is now done inside the + Parameter class, which interprets the array given as an input inside + the parameter file, and returns a dictionary having all relevant fields + initialized. + + .. warning:: + + This used to be an ordered dictionary, for no evident reason. It is + now reverted back to an ordinary dictionary. If this broke + anything, it will be reverted back + + At the end of this initialization, every field but one is filled for + the specified parameter, be it fixed or varying. The missing field is + the 'last_accepted' one, that will be filled in the module :mod:`mcmc`. + + .. note:: + + The syntax of the parameter files is defined here - if one + wants to change it, one should report the changes in there. + + The other fields are + + Attributes + ---------- + initial : array + Initial array of input values defined in the parameter file. + Contains (in this order) `mean`, `minimum`, `maximum`, `1-sigma`. + If the min/max values (**TO CHECK** proposal density boundaries) + are unimportant/unconstrained, use `None` or `-1` (without a period + !) + scale : float + 5th entry of the initial array in the parameter file, defines the + factor with which to multiply the values defined in `initial` to + give the real value. + role : str + 6th entry of the initial array, can be `cosmo`, `nuisance` or + `derived`. A `derived` parameter will not be considered as varying, + but will be instead recovered from the cosmological code for each + point in the parameter space. + prior : :class:`Prior ` + defined through the optional 7th entry of the initial array, can be + ommited or set to `flat` (same), or set to `gaussian`. An instance + of the :class:`prior` defined in :mod:`prior` will be initialized + and set to this value. + tex_name : str + A tentative tex version of the name, provided by the function + :func:`io_mp.get_tex_name`. + status : str + Depending on the `1-sigma` value in the initial array, it will be + set to `fixed` or `varying` (resp. zero and non-zero) + current : float + Stores the value at the current point in parameter space (`not + allowed initially`) + + Parameters + ---------- + value : list + Array read from the parameter file + key : str + Name of the parameter + + """ + # calling the parent method initialization + dict.__init__(self) + + self['initial'] = array[0:4] + self['scale'] = array[4] + self['role'] = array[-1] + self['tex_name'] = io_mp.get_tex_name(key) + if array[3] == 0: + self['status'] = 'fixed' + self['current'] = array[0] + else: + self['status'] = 'varying' + self['prior'] = prior.Prior(array) + + +class Container(object): + """Dummy class to act as a namespace for data""" + pass + + +if __name__ == "__main__": + import doctest + import shutil + from initialise import initialise + folder = os.path.join('tests', 'doc') + cosmo, data, command_line, _ = initialise('-o %s -p test.param' % folder) + doctest.testmod(extraglobs={'data': data}) + shutil.rmtree(folder) diff --git a/notebooks/NEDE.ipynb b/notebooks/NEDE.ipynb new file mode 100644 index 000000000..a44fd7927 --- /dev/null +++ b/notebooks/NEDE.ipynb @@ -0,0 +1,288 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a646b77d", + "metadata": {}, + "source": [ + "# Example of how to run the v7.0 CLASS implementation of Cold New Early Dark Energy" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ca18bca5-9b0a-4e7c-92a9-34ae0c703a35", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from time import perf_counter\n", + "from scipy.interpolate import interp1d\n", + "def interp_onto(xdata, ydata, new_xdata):\n", + " return interp1d(xdata, ydata, fill_value=\"extrapolate\")(new_xdata)\n", + "def get_spectrum(class_instance, lensing=True):\n", + " if lensing:\n", + " cls = class_instance.lensed_cl(2500)\n", + " else:\n", + " cls = class_instance.raw_cl(2500)\n", + " ll = cls['ell'][2:]\n", + " clTT = cls['tt'][2:]\n", + " cl = clTT*ll*(ll+1)/2./np.pi\n", + " return ll, cl\n", + "\n", + "from classy import Class" + ] + }, + { + "cell_type": "markdown", + "id": "c321b3ad", + "metadata": {}, + "source": [ + "#### $\\Lambda$ CDM run to compare with" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "11dcd949-a357-47e2-bc21-95a53aa74ab9", + "metadata": {}, + "outputs": [], + "source": [ + "k_max = 1.0\n", + "kk = np.logspace(-4,np.log10(k_max),1000) # k in h/Mpc\n", + "k_plot = 0.2\n", + "\n", + "LCDM_settings = {\n", + " 'output' : 'tCl, lCl, mPk',\n", + " 'lensing' : 'yes',\n", + " 'P_k_max_1/Mpc' : k_max,\n", + " 'k_output_values' : k_plot,\n", + " 'omega_b' : 0.02238280,\n", + " 'omega_cdm' : 0.1201075,\n", + " 'tau_reio' : 0.05430842,\n", + " 'n_s' : 0.9660499,\n", + " 'A_s' : 2.100549e-09,\n", + " 'h' : 0.67,\n", + " 'N_eff' : 2.038,\n", + " 'YHe' : 0.2454006,\n", + " 'N_ncdm': 1,\n", + " 'm_ncdm': 0.06,\n", + "}\n", + "LCDM = Class()\n", + "LCDM.set(LCDM_settings)\n", + "LCDM.compute()\n", + "ll_lcdm, cl_lcdm = get_spectrum(LCDM)\n", + "pk_lcdm = np.array([k**(3/2)*LCDM.pk(k*LCDM.h(), 0.)*LCDM.h()**3 for k in kk])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0c01511e", + "metadata": {}, + "outputs": [], + "source": [ + "NEDE_settings = {\n", + " 'f_NEDE': 0.23612917, \n", + " 'z_decay_NEDE': 10**3.6134105, \n", + " 'three_eos_NEDE': 1.959447, \n", + " 'Junction_tag': 1,\n", + " 'H_over_m_NEDE': 0.2,\n", + " 'Omega0_NEDE_trigger_DM': 0.3,\n", + " 'NEDE_trigger_fluid_H_m': 0.01,\n", + " 'NEDE_ceff_nature': 'tracking',\n", + " 'sub_dom_cond':1e-6,\n", + " 'start_small_k_at_tau_c_over_tau_h':0.0000001\n", + "}\n", + "\n", + "# These are the recommended precision settings, for which v7.0 has been verified to match older versions\n", + "precision_settings = {\n", + " # No longer uses these old settings from TriggerCLASS versions < 7.0!\n", + " # 'decay_res_enhancement': 100,\n", + " # 'trigger_resolution': 0.005,\n", + "\n", + " 'tol_background_integration': 1e-10, # default\n", + " 'background_integration_stepsize': 1e-3, # ignored when using ndf15\n", + "\n", + " 'tol_perturbations_integration': 1.0e-8,\n", + " 'perturbations_integration_stepsize': 0.5,\n", + " 'perturbations_sampling_stepsize': 0.003,\n", + "\n", + " 'tol_shooting_deltax_rel': 1e-8,\n", + " 'tol_shooting_deltax': 1e-8,\n", + " 'tol_shooting_deltaF': 1e-8,\n", + " \n", + " 'background_evolver': 1, # ndf15 for background, alternatively, use 2 for rkdp45\n", + " 'evolver': 1, \n", + " 'plot_gauge': 'synchronous' # species which gauge to plot quantities in (WARNING: Not tested for Newtonian gauge)\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "809a58af", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ran version 7.0 w. perts in 50.9 s\n" + ] + } + ], + "source": [ + "v7 = Class()\n", + "v7.set(LCDM_settings | NEDE_settings | precision_settings)\n", + "tic = perf_counter()\n", + "v7.compute()\n", + "toc = perf_counter()\n", + "print(f\"Ran version 7.0 w. perts in {toc - tic:.3} s\")" + ] + }, + { + "cell_type": "markdown", + "id": "4b2d9b83-2b50-41d6-bdf2-2ed5ab2d8c4c", + "metadata": {}, + "source": [ + "# 1: CMB Plot" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f1b2131a-3b08-4bff-900f-1330dfa2a14e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ll_v7, cl_v7 = get_spectrum(v7)\n", + "\n", + "fig, ax = plt.subplots(2,1, figsize=[6, 4])\n", + "ax[0].set_xscale('log')\n", + "ax[0].set_yscale('linear')\n", + "ax[0].set_xlim(2,2500)\n", + "ax[0].set_ylabel(r'$C_\\ell^{\\mathrm{TT}}$')\n", + "ax[0].plot(ll_lcdm, cl_lcdm, 'k-', label=r'$\\Lambda$CDM')\n", + "ax[0].plot(ll_v7, cl_v7, '-', label=f\"NEDE v7.0\")\n", + "ax[0].legend(frameon=False)\n", + "ax[1].set_ylabel(r'$\\Delta C_{\\ell}^{\\mathrm{TT}}/C_{\\ell,\\Lambda\\mathrm{CDM}}^{\\mathrm{TT}}$')\n", + "ax[1].set_xscale('log')\n", + "ax[1].set_yscale('linear')\n", + "ax[1].set_xlim(2,2500)\n", + "ax[1].plot(ll_lcdm, np.zeros(len(ll_lcdm)), 'k--', lw=0.8)\n", + "ax[1].plot(ll_v7, (cl_v7 - cl_lcdm)/cl_lcdm, '-', label=f\"NEDE v7.0\")\n", + "ax[1].legend(frameon=False)\n", + "fig.tight_layout()\n" + ] + }, + { + "cell_type": "markdown", + "id": "ae8eca43", + "metadata": {}, + "source": [ + "Crazy spectrum, but that's due to the chosen NEDE parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "b753782c-bcec-485a-b00f-e03245f6cab8", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAFkCAYAAADoo9t2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB8JUlEQVR4nO3dd1gU19fA8e+ydESqgCggKoIdxd5bLLGnagxRY0n5GV+jJtEYY5eYntgSWzSJLUWNpth7ib1ERQRFASkq0jvsvH8QNyKgIAvLwvk82Uf2zsydMxllz87cOVelKIqCEEIIIYSBMNJ3AEIIIYQQxSHJixBCCCEMiiQvQgghhDAokrwIIYQQwqBI8iKEEEIIgyLJixBCCCEMiiQvQgghhDAokrwIIYQQwqAY6zuAikaj0RAZGYm1tTUqlUrf4QghhBAGQ1EUkpKScHV1xcio8OsrkrzoWGRkJG5ubvoOQwghhDBY4eHh1KxZs9DlkrzomLW1NZD7P75q1ap6jkYIIYQwHImJibi5uWk/SwsjyYuO3b9VVLVqVUlehBBCiCfwuGEXMmBXCCGEEAZFkhchhBBCGBS5bSSEEKLMKIoCPP62QFH7io2NJTw8nIiICNLS0sjOzsbKygoHBwfc3Nxwc3N75FMrwjBJ8iKEEKLEkpKSCAwM5PLly1y+fJkrV64QHR3N3bt3iY2NJTk5GY1Go12/SpUq2NjYYGtri42NDfb29tjZ2WFnZ5fnZ0VRyMjIID09nejoaG7dusWtW7cIDw8nLCyMtLS0R8ZlYWGBt7c39erVo27dunh5eeHh4YGFhQVGRkYkJCQQHx9PXFwccXFxxMfHo1KpsLa2pnr16vj4+FC/fn1sbGxK+3+hKAaVcj8NFjqRmJiIjY0NCQkJMmBXCFHhxMXF5UlS7r/Cw8P1FpOTkxNubm5UqVIFY2NjkpOTuXv3LmFhYWRlZelkH66urtSvXx9vb2/s7Oy0+zIyMkKtVmNkZISlpSV169alXr16uLi4SK2vJ1DUz1BJXnRMkhchhCFTFIU7d+4QGhqa53Xt2jUCAwOJiooqdFsXFxcaNGhAgwYNqF+/Pm5ubjg4OODo6Ii1tTVGRkYYGRlpC5HFx8fnufJx7969PH/GxcVhZGSEmZkZpqamODk5UaNGDVxdXXF3d8fd3Z2aNWtibm5eYDzZ2dmEhoYSGBhIcHAwISEhBAcHExkZSXp6OtnZ2dorP/ev9Nja2mrjCwsLe+wxF8bKyoo6depQp04datSoQbVq1XBycsLJySnPz7a2tpLkPECSFz2R5EUIUd4lJibmS07uv27cuEFKSsojt69Zs6Y2SXkwWbG3ty+jIyhb8fHxXLlyhcDAQEJCQkhMTCQ5OZmcnBw0Go32lZCQQHBwMKGhoXlukT2KtbU1tWrVwsPDg5o1a1KjRg3ty83NDQ8PDywtLUv5CMsPSV70RJIXIYS+paenc+PGjQITk9DQUO7du/fI7VUqFa6urnh6euZ51a9fn/r168vvtsfIzMzkxo0bXLt2jWvXrhEdHc3t27e5ffs2d+7c0f6cmJhYpP6cnJyoVauW9lW7dm3q1KlD3bp1cXNzQ61Wl/IRlR1JXvREkhchRFlITk4mJCQk3+vatWtEREQ8dntHR8d8yYmnp6f2KoCZmVkZHEXllpaWRlhYmDaxvD8Y+f4rLCyMpKSkR/ZhYmKCp6enNpl58E9PT0+DO4+SvOiJJC9CCF3KyckhJCSEf/75hwsXLmj/vH79+iO3q1KlSoHJyf0ExcqqConpWdxLySQuNZN7KVmkZmaTnaOQlaMhKyf3toeZiRpzEzXmxkbYWJjgVNUcJ2szrMzkYdXSpigK8fHx3Lhxgxs3bnDz5k3t+KNr165x/fp1MjMzC91epVLh7u5OvXr18Pb2xsfHR/tnjRo1yuVYG0le9ESSFyFESURFRXH8+HHt6+TJkyQnJxe4rqOjI15eXtpv2/dfderUwcHBAUWBm/dSuRKVyPW7KUTEpRJ2L5Xwe2lExqeRrXnyX/9WpmrcHayo61QFL6cqeLtY09zdjmrWhvVN35Dl5ORw69Yt7RW3a9euaX8OCQkp9O8N5A4o9vb2zpfUeHl56XWMjSQvelLRk5ejR4/Svn17evXqxfbt2/Mtj46OZt68efzxxx/cunULJycnfH19mTBhAt27dwdgxIgRrFmzBgBjY2Ps7e1p0qQJQ4cOZcSIEdqCUvfXe+211/jmm2/y7OfNN99k6dKlDB8+nNWrV5fuQQtRShRF4fr16+zbt4+9e/dy5MgRwsLC8q1naWlJw4YNadKkCY0bN9a+qlWrpl0nR6MQFJ3E6bA4LkcmEBiVRFB0EmlZOY+MwdrMGDsrU+wsTbAyM8ZEbYSJ2ghTYxWKAulZOaRnaUjNyiEhNZPbSRmkZhbep4eDJX7udnSqV40u3tWwtTR98v9B4ondf2osJCSEoKAgrly5ov3z2rVrZGdnF7qth4cHPj4+NGzYUPtq0KDBYydL1AVJXvSkoicvo0eP5tixY1y5coXQ0FDc3d21y27cuEH79u2xtbVl1qxZNGnShKysLHbs2MGyZcu4cuUKkJuUxMTE8N1335GTk0NMTAzbt28nICCAjh07snXrVoyNjRkxYgR79+4lMTGRqKgoLCwsgNzBiNWrV6dq1ap07dpVkhdhUCIjI9m1a5c2YXm4PopKpaJRo0a0bt2aNm3a0Lp1a+rXr59vUGZ6Vg6nb8ZxIvQeZ8LiOBsWT3JG/g8kU2MjvJ2tqetUBTd7S9zsLHC3t6SmvSXVqphhalz86rMpGdlEJ6YTeieFkDvJBMckc/FWAldvJ/HgJ4qRClp42NO7kQsDfV1xqCJXZcqDrKwsrl+/ni+puXLlyiMHc7u7u9OgQYN8SU2VKlV0FpskL3pSnORFURRSU1PLKLK8LC0ti32/MyUlBRcXF3744QdmzJjBs88+y4cffqhd/vTTT3PhwgWCgoKwsrLKs218fDy2trZAbvISHx/Pli1b8qyzd+9eunfvzvLlyxk9erR2vevXr/Pee+8xbNgwANatW8dHH31E7dq1sbW1leRFlGs5OTmcOHGCP/74gz/++INz587lWW5iYkKbNm3o2rUrnTt3pmXLlgV+w9VoFK5EJ3Eo+A6HQ+5yIvQeGdl5H8e1MlXTzN2OJjVtqF+9KvWrW1PLwQpjddmUx09Iy+JceDx/X49lb+BtgmL+G2xqbKSim48TL7Rwo6uPE2qj8jfeQsDdu3e1j4VfunRJ+yqs1o2bm1uBVwufVFE/Q2XElR6lpqbqNGMtjuTk5HwJxuNs3LgRMzMz+vbty/Xr11m4cCHTp09HpVJx7949tm/fzrx58wrs937i8ijdunWjadOmbNq0idGjR2vbR44cyXfffadNXlatWsWrr77K/v37ixW/EGUlKSmJP//8k23btrF9+3ZiY2O1y1QqFS1atKB79+5069aNdu3aFfpvMSUjmwNX77DrcgyHgu9wNznv4EyXqua0qW2PXy17/Nzt8Hax1mtSYGNhQud61ehcrxrv9fYh/F4quwNj2Hz2FhciEth5OYadl2PwdLRiVAdPnvOriblJxXnMtyJwdHSkQ4cOdOjQIU/7vXv3uHz5cp6E5tKlSzRo0EAvcUryIops5cqVDB06FBMTE4YNG8Z7773Hnj176NGjByEhISiKgo+PT4n24ePjw4ULF/K0+fv7M3XqVG7cuIFKpeLIkSNs2LBBkhdRrsTHx7Nt2zZ++eUXduzYQUZGhnaZra0tvXr1om/fvvTu3TvPWJWH3UnKYHdgDLsux3A45C6ZD1xdsTRV06a2Ax3qOtKpniN1qlUpl0+M3Odmb8nI9p6MbO9JUHQSv5wO56dTEYTeTeGDLRf5fNdVxnSszYh2tbAwlSSmPLO3ty8wqXnw73lZkuRFjywtLR85Gry0910cQUFBHD16lC+//BIAZ2dnevXqxapVq+jRo4fOZopVFCVfH46OjvTt25c1a9agKAp9+/bF0dGxRPsRQhfu3r3Lb7/9xq+//sru3bvzzKNTr149Bg0aRL9+/Wjbti3GxoX/ur2dmM7vF6L4458ozoTF5Rk3UsvBkp4NXejq7YSfh90TjVEpD7xdrJnWtwETetTj51PhrDgcSkRcGgu2X+G7I6GM7+7Fiy3dMCmjW1xCN/RVR0aSFz1SqVTFvnWjLytXrqR+/fq0bNlS2zZ8+HD8/f2Ji4vDy8sLlUpFYGAggwYNeuL9BAYG4unpma/91VdfZdy4cQAsXrz4ifsXoqRSU1PZunUrP/74I9u3bycn578nbxo2bMhzzz3Hc889R8OGDR+ZzMenZvLXxWi2novk79DYPAlL05o29GzoQs8GztR1Kt9XV4rLysyYEe09ebmNB1vPR/L5rqtExKXxwZaLrDwcyof9G9DV20nfYYpyTpIX8VjZ2dl8//33TJgwIU/7gAEDsLS0ZO3atYwbN45evXqxePFixo8f/8gBu4XZu3cv//zzD2+//Xa+Zb1799YWY+rVq1eJjkeI4srJyWHfvn38+OOP/Prrr3mumPr6+vLcc8/x7LPPPva2aXpWDjsu5SYsB4PvkJXzX8bS3N2WAU1d6d2oOi42BU80WJEYq414pnlN+jVxZf2JMBbuDSb0bgojvzvJUw2c+bBfA9zsK8+cPqJ4JHkRj/X7779z584dXn755TztZmZmvPjii6xcuZJx48axZMkS2rVrR6tWrZg9ezZNmjQhOzubXbt2sXTpUgIDA7XbZmRkEB0dne9R6X79+vHKK6/ki0GtVmu3r0jzeIjy7cKFC3z//fesW7cuz9MWtWrV4uWXX2bYsGGPTVgUReFceDw/n45g27lIkh54nNnHxZoBvq70b+JaaT+oTY2NGN6uFs80r8HXe4L57sgNdl2O4eDVO7zeuQ5vdKkjg3pFPjpJXrZu3VrsbZ566ilt3Q5Rvq1cuZJu3bpRs2bNfMuGDx/ON998w5kzZ2jevDlnzpxh3rx5TJo0iaioKKpVq4afnx9Lly7Ns9327dupXr06xsbG2NnZ0bRpU77++muGDx+uLVL3sIpYN0eUP4mJiaxfv56VK1dy8uRJbbudnR0vvPAC/v7+tGvX7rG3cm4npbPl7C1+OhVByO3/rtTUsLXgmeY1GNDUFS/n0i/6ZSiszU2Y1rcBL7RwY8bWSxy9FstXe4LZfPYWswY0pKuP3EoS/9FJnZfCPmwK3alKRXBwMLVr1y7prsudil6kToiKSFEUjh49yooVK/jpp5+09ZdMTEzo378//v7+9OnT57GDE3M0Cnuv3GbjyTD2Bd0h59/y++YmRvRpVJ3n/WrSprYDRlLj5JEUReHPf6KZ8/tlohPTAejV0JkP+zekhq186a3IyrzOS3R0NE5ORcuMy6LEsBBCPM7t27f5/vvvWbFiBUFBQdr2+vXrM3r0aPz9/R/5WLO2n8R0NpwMZ8OJMCIT0rXtzdxted7PjX5Nq1PV3KRUjqEiUqlU9G1Snc7e1fhq91VWHbnBjksxHLx6l/HdvRjVwdNgn7oSuqGT5GX48OHFugX08ssvy1UJIYReKIrCgQMHWLJkCZs3b9bO8WJpacmQIUMYNWoUbdu2fextIUVROHYtlh+P32TnpRjtJId2liY838KNF1rUpK6TfFEriSpmxkzr24Bn/Wry4ZZLnLhxjwXbr/DrmQjmDGxE2zoO+g5R6IlMD6BjcttIiPIpKSmJH374gSVLlnDp0iVte+vWrRk9ejQvvvhika4KJ6Rm8cuZCNYev8n1Oynadj8PO15u406fRtVlgGkpUBSFTWduMf/PQGJTcp88HOTryvt96+NkXfGfzqosZG4jPZHkRYjy5dKlSyxZsoTvv/9e+4izlZUV/v7+vPHGGzRp0qRI/QRFJ/HdkVC2nLtFelZu1VsrUzWDmtXg5TYe1K8u/97LQkJqFp/uDOLH4zdRlNxZsSf1rMfLbTzKbA4nUXrKLHmJi4tDURTs7e25c+cOBw8exNvbm0aNGpWkW4MlyYsQ+peVlcWWLVtYvHgxBw4c0Lb7+Pjw5ptv8sorr2BjY/PYfjQahf1Xb7Pq8A0Oh9z9rx8Xa15u48GgZjWoYiYVJ/ThQkQ8H2y5yIWIBCC3EvHbT9WjfxNXGRBtwMokeVmxYgUBAQFoNBreffdd1q5dS5MmTTh48CDjx49n7NixT9q1Xg0ePJj9+/fTvXt3fvnll2JtK8mLEPpz9+5dvvnmG5YuXUpkZCSQWxdo4MCB/O9//6Nr165FqlabkpHNr2ci+O7IDULv5t4aMlJB70YujGzvSQsPuwpV9dZQ5WgU1p8I4/NdV7n3760kb2drxnf3oldDZ7kSY4DKJHlp2rQpx48fJzU1FXd3d0JDQ6lWrRqJiYl06tQp39TvhmLfvn0kJyezZs0aSV6EMACXLl3iyy+/5McffyQ9PfdpH2dnZ8aMGcNrr71WYI2igoTfS+X7YzfYcDKcpPTcgbzW5sYMbeXOK209qGlXOQvJlXfJGdl8dziUZYeua89bDVsLRravxQst3eRJLwNSJo9Kq9VqzM3NMTc3p27dutpHCqtWrWrQ30q6du0qMxYLUc4pisKOHTv44osv2Llzp7a9RYsWTJgwgeeffx5TU9Mi9XX65j1WHAplx6Vo/n1oCE9HK0a2r8WzzWtiJbeGyrUqZsa81d0L/7YerDocyg9/3+RWfBpz/wjks51XGdSsBq+0lXFJFUmJrqkZGxtrv+U8eF85KSmpZFGVwMGDB+nfvz+urq6oVCq2bNmSb50lS5bg6emJubk5fn5+HDp0qOwDFUI8kbS0NJYtW0bDhg3p06cPO3fuxMjIiGeeeYZDhw5x4sQJhg0b9tjERaNR2HU5hmeXHuXZpcf462Ju4tKhriOrRrRgz8TOvNK2liQuBsTW0pSJPb05NrU7Ac80xsupCmlZOaw/EUafrw7x3NKj/HbuFpnZGn2HKkqoRMnL3r17tRUnHxz8lpaWxsqVK0sW2RNKSUmhadOmLFq0qMDlGzduZMKECUybNo2zZ8/SsWNH+vTpQ1hYWBlHajhGjBiBSqXio48+ytO+ZcuWPFfY9u/fj0qlKvAVHR0NwMyZM7VtxsbGODo60qlTJ7788ksyMjLy9N+lS5cC+3r99ddLfCwPvxo2bPjI7cLCwujfvz9WVlY4Ojoyfvx47USRomxERUXxwQcf4ObmxmuvvUZgYCDW1tZMmDCBkJAQfv31Vzp06PDYq74Z2Tn8dDKcp744wJjvT3H6ZhymaiNeaFGT7RM68uPo1nTzcZZBnwbM3ETN0Fbu7Hy7ExvGtqFv4+oYG6k4dTOO/9twjnYf7eHL3VdJzcx+fGeiXCrRV4oqVaoU2O7k5FTkaru61qdPH/r06VPo8s8//5xRo0YxevRoAL788kt27NjB0qVLCQgIKPb+MjIy8nzoJiYmFj9oA2Bubs6CBQt47bXXsLOze+S6QUFB+e5VPvj3oWHDhuzevRuNRkNsbCz79+9n7ty5/PDDD+zfvz9PrY0xY8Ywe/bsPH1ZWj75uIOvvvoqTxKWnZ1N06ZNef755wvdJicnh759+1KtWjUOHz5MbGwsw4cPR1EUFi5c+MSxiKK5fPkyn3zyCWvXriUrKwvInRhx/PjxjBo1qshjyxLTs1h3PIxVh0O5nZT7b9bazJhhbTwY2b4WzlWlVkhFo1KpaFPbgTa1HYhJTGf9iTDWHQ/jdlIGX+4OZsOJcGYNbEivhi76DlUUU6lcD92zZw979uzh9u3baDR5L8+tWrWqNHZZJJmZmZw+fZopU6bkae/ZsydHjx59oj4DAgKYNWuWLsIr13r06EFISAgBAQF8/PHHj1zXyckJW1vbQpcbGxvj4pL7y8LV1ZXGjRvz1FNP0bRpUxYsWMDcuXO161paWmrXfZxvv/2W2bNnEx4enme+rQEDBmBnZ8eaNWuwsbHJc5Vwy5YtxMXFMXLkyEL73blzJ5cvXyY8PBxXV1cAPvvsM0aMGMG8efNkYHYpOXz4MB9//DHbtm3TtrVv3563336bgQMHYmxctF9fMYnprDoSyrq/w7QzOjtXNWNUB0+GtnLHWgZzVgrOVc2Z0KMe/+tal78uRvPJjiuE30vjtR9OM6y1O9P7NZDiggZE58+RzZo1i549e7Jnzx7u3r1LXFxcnpc+3b17l5ycHJydnfO0Ozs7a29rAPTq1Yvnn3+eP//8k5o1a+aZWfZhU6dOJSEhQfsKDw8vcjyKopCama2XV3EfMlOr1cyfP5+FCxcSERFRrG2LwsfHhz59+rBp06Yn7uP555/n7t277Nu3T9sWFxfHjh07GDZsWIHbrFy5kh49euDh4VFov8eOHaNRo0baxAVy/45kZGRw+vTpJ45X5KfRaPjtt99o3749HTt2ZNu2bahUKp555hmOHTvG4cOHefbZZ4uUuITcTuLdX87TYcFevj1wnaSMbLycqvDJc0049G43xnaqI4lLJWSiNmJAU1d2vd2Z1zrnTg689ngYgxYf4WZsymO2FuWFzq+8fPPNN6xevRp/f39dd60zD98TVxQlT9uOHTuK3JeZmdljZ5otTFpWDg0+LPq+dOny7F5Ymhbv9A8ePBhfX19mzJjxyDFNDz+WWqNGjTyT3hXGx8cnz1MjkDu4esWKFXnaFi9ezPDhw/Ntb29vT+/evVm3bh3du3cH4Oeff8be3l77/kFRUVH89ddfrFu37pFxRUdH50t47ezsMDU1zZP0iieXkZHB2rVr+eSTT7hy5QoApqamDB8+nEmTJuHt7V3kvi7eSmDR3hC2X/rv3LSqZc9rnWvT1dtJxrIIIHdczNQ+9elQ15G3N57nSnQS/Rce5quhzejqrZ9hD6LodJ68ZGZm0q5dO113qxOOjo6o1ep8Hzi3b9/O9+EkCrZgwQK6devGpEmTCl3n0KFDecatFPXy/sNJJMCwYcOYNm1anrZHjacaNmwYY8eOZcmSJZiZmbF27VqGDBmCWp3/cvDq1auxtbVl0KBBj42toEGgBcUriicxMZFly5bxxRdfaIvKVa1alTfffJPx48dTvXr1Ivd16sY9Fu0LYX/QHW1bzwbOvNa5Dn4ejx6nJSqvjl7V+P2tDryx9jRnw+J5dfVJJv57e0kS3fJL58nL6NGjWbduHdOnT9d11yVmamqKn58fu3btYvDgwdr2Xbt2MXDgwDKPx8JEzeXZvcp8v/f3/SQ6depEr169eP/99xkxYkSB63h6ej5yzEthAgMD8fT0zNNmY2ND3bp1i9xH//790Wg0/PHHH7Rs2ZJDhw7x+eef51tPURRWrVqFv7//Yx+pdXFx4fjx43na4uLiyMrKkqT3CUVHR/PVV1+xdOlSEhJyy7u7urry9ttvM3bs2CKPI1IUhSMhsSzcG8zx0HtAbiXcgb41eLNLHbycZVZn8XguNuZsGNuG2dsus/Z4GJ/tusqFWwl89kJTKXBXTukkeZk4caL2Z41Gw7Jly9i9ezdNmjTBxCTviS/og0SXkpOTCQkJ0b4PDQ3l3Llz2Nvb4+7uzsSJE/H396dFixa0bduWZcuWERYWVqLHb5+USqUq9q2b8uCjjz7C19eXevXq6azPK1eusH37dqZOnVqifiwsLHjmmWdYu3YtISEh1KtXDz8/v3zrHThwgJCQEEaNGvXYPtu2bcu8efOIiorSXgnYuXMnZmZmBfYtChcWFsbHH3/MihUrtE/p+fj48O677xapNst9iqKwJ/A2C/eFcD48HgATtYrn/Gryeuc6eDhYldYhiArKzFjNvMGNaVrTlg9+u8iuyzEMWnSEb/z9qCdJcLmjk0/Os2fP5nnv6+sLwMWLF/O0l8Ul9lOnTtG1a1ft+/uJ1fDhw1m9ejUvvvgisbGxzJ49m6ioKBo1asSff/75yAGbIq/GjRszbNiwQh8Tvn37trZ44X0ODg7aRDY7O5vo6Oh8j0r7+vryzjvv5NkuNTU1320+MzOzRz6uPWzYMPr378+lS5d4+eWXC1xn5cqVtG7dusAJRDdv3szUqVO1Yy969uxJgwYN8Pf355NPPuHevXtMnjyZMWPGyJNGRRQcHMxHH33E999/T3Z27hM/bdu2ZcqUKfTr1y/P02GPkqNR+POfKBbvC+FKdG4xTDNjI4a2cmdsp9q42lqU2jGIyuGFlm54u1jzxo+nuX43hb5fH2Jke0/e7FIHW8uiJdeiDCg6MmXKFOXvv//WVXcGKyEhQQGUhIQEfYeiM8OHD1cGDhyYp+3GjRuKmZmZ8uBfoX379ilAga9jx44piqIoM2bM0Lap1WrF3t5e6dChg/LFF18o6enpefbRuXPnAvvq1avXI+PNzs5WqlevrgDKtWvX8i2Pj49XLCwslGXLlhW4/Xfffac8/E/j5s2bSt++fRULCwvF3t5eGTduXL54RX7//POPMnToUMXIyEh7/rp3767s27dP0Wg0Re4nMztH+elkmNL1k32Kx3u/Kx7v/a40mP6XEvBnoHI7Uc6D0L27SenKqNUntH/f6k//S5nx20UlLDZF36FVaEX9DC3RxIwPGjlyJH/88QdqtZr+/fszaNAgunfv/sRP4hgqmZhRiNwroPPmzcszPUe/fv2YNm0abdq0KXI/Gdk5/HwqgqX7r3ErPg0AGwsTRravxYh2teSbsCh1+67c5uMdQQRG5RYgVamgR31nRrarRds6DjJoX8fKZFbphymKwuHDh9m2bRtbt27l1q1bPPXUUwwYMIB+/frh6Oioq12VW5K8iMrs0KFDzJs3T1tuQKVS8dxzz/H+++9rbycXxf2kZcm+ECITcm9BOlYxZUzH2gxr40EVmW9IlCFFUTgccpflh0I5ePW/p9kaulZlRv+GtPK012N0FYtekpeHBQYGsm3bNn777TdOnTpF69atGTBgAEOHDqVGjRqltVu9kuRFVDaKorBr1y7mzZvHwYMHgdyihsOGDWPq1Kn4+PgUua+Ckhbnqma80bkOQ1q5SwVUoXcht5NZc/QGv56JIDUzB4AhLd2Y0b8hFqby97OkykXy8qA7d+6wdetWtm7dSseOHZk8eXJZ7LbMSfIiKgtFUdi2bRtz587VVqE2NTVl5MiRvPfee/kee3+UwpKWN7vU5cWWbpK0iHLnXkomn+4MYv2JMBQF6jlXYfFLzeXx/BIqd8lLZSHJi6joFEVh69atzJw5k3PnzgG5j6i/9tprTJ48uVhXVTOyc/jp36QlSpIWYYCOXrvL/204x52kDCxN1Xz8XBP6NXF9/IaiQGWWvMTFxaEoCvb29ty5c4eDBw/i7e1d4COolYEkL6KiUhSF3377jVmzZmmTlipVqjBu3DjefvvtYs0kL0mLqEjuJGXwfxvOcvRaLABjOnryXm8fjNU6nz6wwiuT5GXFihUEBASg0Wh49913Wbt2LU2aNOHgwYOMHz+esWPHPmnXBkuSF1HRFJa0/N///R9vv/02Dg4ORe5LkhZRUWXnaPhkZxDfHrgOQJva9nw9tBlO1uZ6jsywlEny0rRpU44fP05qairu7u6EhoZSrVo1EhMT6dSpk/YXXWUiyYuoKApKWqytrRk/frwkLUIU4q9/opj883lSMnOwNjfm7R71GNbGHTNj+TteFEX9DC3R84ZqtRpzc3PMzc2pW7cu1apVA3InVpNn34UwTBqNRpu0nD9/HpCkRYii6tO4Ol7OVXh743n+uZXA7N8v8+3Ba4zuUJuhrd3lMX8dKdH/RWNjY9LT0zE3N+fAgQPa9qSkpBIHJoQoW4UlLfdvD9nbF72WRVaOhk1nIvh6T4i2uJwkLaKyqOtkzZb/tWfDyTC+3hNMTGIG8/4MZNG+EN7oUocR7WrJv4ESKtFto+TkZKysrPJdZbl9+zYRERE0b968xAEaGrltJAyNRqNhy5YtzJo1iwsXLgBPnrTkaBS2nr/Fl7uDuRmbCoCTtRn/6ypJi6icMrJz+O1sJN8cvMb1OykAVLcxZ+6gRnSvL7PSP0weldYTSV6EodBl0qLRKPx1MZovdl8l5HYyAA5WprzRpQ4vt/GQpEVUejkahS1nb/HZziBtLaMhLd34oF8DuZX0AL0lLwEBATg7O/Pqq6/maV+1ahV37tzhvffe0+Xuyh1JXkR5d79Oy4cffljipEVRFPYE3uazXVe1c7/YWJgwtlNtRrSrhZX8UhYij/SsHD7fdZXlh66jKOBmb8Fnz/vKFAP/0lvyUqtWLdatW0e7du3ytB8/fpwhQ4YQGhqqy92VO5K8iPJKURR27NjB9OnTOXXqFFCypOVQ8F0+23WV8+HxAFQxM2ZUB09GdfSkqrlJaRyCEBXG39djmfTTeW7Fp6FSwdiOtXn7qXqV/iql3pIXc3NzAgMD85UGv379Og0aNCA9PV2Xuyt3JHkR5dG+ffv44IMPOHr0KABWVlaMHz+eyZMnFytpgdxfup/vvMqJG/cAsDBRM6J9LcZ2rI2dlczyLERRJaVnMef3y/x0KgLIHdQ+vrsXL7Rww6SSFrgrk0elC+Lm5saRI0fyJS9HjhzB1VVKJgtRlo4cOcL06dPZt28fkPvl4n//+x/vvvtusSriApwJi+PznVc5HHIXAFNjI15u7cEbXepQzdpM57ELUdFZm5vw8XNNeaqBCzO3XuJWfBrTNl/kmwPXeKubF880qyFVeguh8+Rl9OjRTJgwgaysLLp16wbAnj17ePfdd5k0aZKudyeEKMCpU6eYPn0627dvB8DExITXXnuNqVOnFvtLxMVbCXy+6yp7r9zO7Uut4sWWbozr6oWLjVQPFaKknmrgTKd6jqw/HsaifSGE30vj3V8usHhfCJN6etO/SXWpnfYQnd82UhSFKVOm8PXXX5OZmYmiKFhYWPDee+/x4Ycf6nJX5ZLcNhL6dOHCBWbMmMGWLVuA3EKSr776Kh988AHu7u7F6utqTBJf7LrKXxejc/syUvFs8xq81c0LN3tLXYcuhADSMnP48e+bfHPgGrEpmQD4edgxvV8DfN1s9RtcGdD7o9LJyclcvnwZCwsL6tWrh5lZ5bisLMmL0IcrV64wc+ZMNm7cCICRkRHDhg3jww8/pG7dusXq6/qdZL7aE8zW85EoCqhUMLCpK//Xox6ejlalEb4Q4iGpmdmsOBTK0v3XSMvKAWBwsxq829ub6jYWeo6u9Og1eVm5ciVffPEFwcHBAHh5eTFhwgRGjx6t612VO5K8iLJ07do1Zs+ezY8//ohGowHghRdeYObMmdSvX79YfUXEpfL1nmB+PXOLHE3ur4WnG7swoUc96jlb6zx2IcTjxSSm88mOIH45nTuo19zEiLGd6jC2U+0KWR9Gb8nL9OnT+eKLL3jrrbdo27YtAMeOHWPRokX83//9H3PnztXl7sodSV5EWQgLC2Pu3LmsWrWKnJzcb2UDBw5k9uzZNGnSpFh93UnKYPG+ENYev0lWTu6vg+4+Trz9VD0a1bDReexCiOL7JyKBOb9f1j7lZ2tpwqj2ngxvX6tClSbQW/Li6OjIwoULGTp0aJ729evX89Zbb3H37l1d7q7ckeRFlKaoqCjmz5/PsmXLyMzMvR/eu3dvZs+eTcuWLYvVV0JaFssOXmPV4Rvay9Lt6zowqac3zd3tdB67EKJkFEVh+8VoPtkZpJ1qwNrcmJHtPXm1fS1sLQ2/VIHeHpXOycmhRYsW+dr9/PzIzs7W9e6EqBTu3LnDggULWLx4sbZWUteuXZkzZw7t27cvVl+pmdmsPnqDb/ZfIzE9999kUzdb3uvlTbu6jjqPXQihGyqVij6Nq9OzoQt//BPFwj3BBN9O5us9waw6HMorbT0Y3bE29pWg3pLOr7y89dZbmJiY8Pnnn+dpnzx5MmlpaSxevFiXuyt35MqL0KX4+Hg+/fRTvvzyS1JScr9ptWvXjjlz5mhLERRVZraGDSfDWLg3hDtJGQDUc67C5J7ePNXAWR7FFMLA3J9TbOHeYK5EJwG5RSMHN6/B8La18HYxvLFqertt9NZbb/H999/j5uZGmzZtAPj7778JDw/nlVdewcTkv3tzDyc4FYEkL0IXUlNTWbhwIQsWLCAuLg7IvXo5d+5cevXqVaxE4/6EcF/svkpEXBqQO5/KxKfqMaBpDdRGkrQIYcg0GoXdgTF8vTeYi7cSte1tatszol0tetR3Nphid3pLXrp27Vqk9VQqFXv37tXlrssFSV5ESWRmZrJ8+XLmzp1LdHRufZWGDRsyZ84cBg0aVKykRVEUdlyK4bOdQQT/O9NzNevc8uMvtnDD1NgwfpkJIYpGURSOh95jzdEb7Lwco31q0NXGnGFtPBjayr3c31LSe52XykqSF/EkcnJyWLt2LTNmzODGjRsAeHp6MmvWLF566SXU6uJN1nY4+C6f7LjC+YgEIHem59c712FEu1pYmFbuid+EqAwi49NYe/wm60+Ec+/fYnemxkY8Vd+Zwc1q0KletXL5BUaSFz2R5EUUh6IobNmyhQ8++IDLly8D4OLiwvTp0xk9ejSmpsX7lnQmLI5PdwRx9FosAJamal5t78mYTrWxsag4j1MKIYomPSuHPy5EsebYDS78+2UGwM7ShP5NXRncrAa+brblZsxbmScvr776apHWW7VqlS52V25J8iKKavfu3bz//vucPHkSADs7O6ZMmcK4ceOwtCxe+f2g6CQ+3RnErssxAJiqjRjWxp03u9SVSROFECiKwqXIRDafvcVv5yK5m5yhXVbb0YqBvjXo3ciFes5V9JrIlHnyYmRkhIeHB82aNeNRXW7evFkXuyu3JHkRj/P3338zbdo07ZgvKysr3n77bSZNmoStrW2x+gqLTeWL3VfZcu4WigJGKnjOrybju3tR007mHxJC5Jedo+HItVg2n4lgx6UYbZ0nAA8HS3o2cKZnQxeau9uV+YD+Mk9e3nzzTTZs2IC7uzuvvvoqL7/8Mvb29rro2qBI8iIK888///DBBx+wdetWAExNTXnjjTeYOnUqzs7OxeorJjGdhXuD2XAinOwHSvlPfMqbuk5VdB67EKJiSs7IZsfFaP78J4pDIXfJzNZolzlYmdLNx4nO3tVoX8cRuzIY7KuXMS8ZGRls2rSJVatWcfToUfr27cuoUaPo2bNnubmfVtokeREPu3btGjNmzGDdunUoioKRkREjRoxgxowZxZ7pOS4lk28OXmPN0RukZ+X+kulUrxrv9PSmcU0p5S+EeHIpGdkcvHqHnZdj2BMYoy1iCbkTtDapYUNHr2p09HKkmbtdqQz41fuA3Zs3b7J69Wq+//57srKyuHz5MlWqGMY3wsGDB7N//366d+/OL7/8UqxtJXkR90VGRjJnzhxWrFihrS79/PPPM3v2bHx8fIrVV0pGNqsOh7Ls4HWSMnL78vOw451e3rSp7aDz2IUQlVtWjobj1++xP+g2h4LvEhSTlGe5pamaFrXsaVfHgdc61dbZBQq9TQ9wn0qlQqVSoSiKdrZbQzF+/HheffVV1qxZo+9QhAGKjY1lwYIFLFy4UFvKv0+fPsydO5fmzZsXq6/0rBzWHQ9j8b4QYv993NHHxZp3e3vT1dup0lzRFEKULRO1ER28HOnglTtlSExiOoeC73Io+A6Hg+8Sm5LJwat3uJ2Yzuud65R5fDpNXh68bXT48GH69evHokWL6N27N0ZG5e958sJ07dqV/fv36zsMYWCSkpL48ssv+fTTT0lMzK1y2b59ewICAujYsWOx+srO0bDpzC2+3H2VyITcBKiWgyVvP1WP/k1cMZKquEKIMuRc1Zzn/GrynF9NNBqFoJgkjl2LxcpMP3WjdJa8PDhgd+TIkWzYsAEHB91fzj548CCffPIJp0+fJioqis2bNzNo0KA86yxZsoRPPvmEqKgoGjZsyJdfflnsDw8hiio9PZ2lS5cyf/587azpvr6+zJs3jz59+hTr6sj9uUo+2/XfrLEuVc0Z392L51vUxMRASnwLISouIyMV9atXpX51/Q2N0Fny8s033+Du7o6npycHDhzgwIEDBa63adOmEu0nJSWFpk2bMnLkSJ599tl8yzdu3MiECRNYsmQJ7du359tvv6VPnz5cvnxZOzjSz8+PjIyMfNvu3LkTV1fXEsUnKo/s7GxWr17NrFmziIiIAMDLy4s5c+bw/PPPF+tqo6IoHAq+y8c7rmjnJrGzNOHNLnXxb+uBuYlUxRVCiPt0lry88sorZXL/vU+fPvTp06fQ5Z9//jmjRo1i9OjRAHz55Zfs2LGDpUuXEhAQAMDp06d1Fk9GRkaeROj+7QJRcWk0Gn7++WemT59OcHAwADVr1mTmzJkMHz4cY+Pi/bM6GxbHx9uDOHY9tyqulama0R1rM7qjJ9bmUhVXCCEeprPkZfXq1brq6ollZmZy+vRppkyZkqe9Z8+eHD16tFT2GRAQwKxZs0qlb1G+KIrCX3/9xbRp0zh37hwAjo6OTJs2jddffx1zc/Ni9RdyO5lPdwSx/VLuBIymaiP823rwZpc6OFSRqrhCCFGYUnvaSB/u3r1LTk5OvoJfzs7O2hl6i6JXr16cOXOGlJQUatasyebNm2nZsmWB606dOpWJEydq3ycmJuLm5vZkByDKrUOHDvH+++9z+PBhAKpWrcrkyZOZMGEC1tbWxeorKiGNL3cF8/PpcDT/VsV9pnlNJvSQqrhCCFEUOkleLly4QKNGjYp8j//SpUt4e3sX+/J6UT18+0pRlGLd0tqxY0eR1zUzM8PMTL4lV1QXLlxg6tSp/PnnnwCYm5vz1ltv8d577xV7QHp8aiZL9l9j9dEb2iqWTzVw5p1e3tRzLl4CJIQQlZlOsodmzZoRHR1NtWrVirR+27ZtOXfuHLVr19bF7rUcHR1Rq9X5rrLcvn272OXXReV2/fp1PvzwQ21VXGNjY0aPHs306dOLPag7NTOb747c4JsD10j6t2Jlq1r2vNfHGz+PyjeFhhBClJROkhdFUZg+fXqRZ8LNzMzUxW7zMTU1xc/Pj127djF48GBt+65duxg4cGCp7FNULDExMcydO5dvv/2WrKwsAIYMGcKcOXOoW7dusfrKytGw4WQ4X+8J5k5S7qBuHxdr3uvtQxfvalJgTgghnpBOkpdOnToRFBRU5PXbtm2LhYXFE+0rOTmZkJAQ7fvQ0FDOnTuHvb097u7uTJw4EX9/f1q0aEHbtm1ZtmwZYWFhvP7660+0P1E5JCYm8umnn/L555+TkpJbX6VXr17Mnz+/2FVxNRqF3/+J4rOdQdyMTQXAzd6CSU95M6CpFJgTQoiS0knyUpbVaE+dOkXXrl217+8Plh0+fDirV6/mxRdfJDY2ltmzZxMVFUWjRo34888/8fDwKLMYheG4X2Bu3rx5xMbmPqrcqlUrPvroozx/z4pCURQOBt/l4+1XuBSZ+8i8YxVT3urmxdBW7qUyiZkQQlRGpTYxY2UlEzMahpycHL7//ntmzJhBeHg4AD4+PsyfP59BgwYV+5bOw7VaqpgZM7ZTbUZ18MTKrEI91CeEEKVG7xMzClEeKYrCb7/9xrRp07h8+TKQW2Bu1qxZvPLKK8V+Ai7kdhKf7riar1bL/7rWxd7KVOfxCyGEkORFVCIHDhxgypQp/P333wDY29vz/vvv87///a/YBeYi49P4anf+Wi1vP1WPGrZPNp5LCCFE0UjyIiq8c+fOMXXqVLZv3w6ApaUlb7/9Nu+88w42NjbF6isuJZOlB6RWixBC6FOZJC/fffcdI0eOLItdCaF17do1pk+fzvr16wEwNjZm7NixTJ8+HRcXl2L1pa3Vsv8aSRn/1mrxtOe93j74edjpPHYhhBCFK5PkZdOmTdSqVUv79EZaWhqjR49m7dq1ZbF7UclER0czZ84cli1bRnZ2bqIxdOhQ5syZQ506dYrVV0G1WupXr8q7vb3pUk9qtQghhD6USfLy448/0qdPH1atWoVarWbo0KG89tprZbFrUYkkJCTwySef8MUXX5CamltfpXfv3gQEBODr61usvgqr1TK5pzf9m0itFiGE0KdSTV4mTpyIr68vvr6+rFq1ipdeeglFUVi1ahXNmjUrzV2LSiQ9PZ3Fixczf/587t27B0CbNm0ICAigS5cuxepLarUIIUT5V6rJS+fOnblw4QLbtm3jypUrREZG0qZNG3bu3ElkZCR9+/Ytzd2LCi47O1tbqyUiIgKA+vXrM3/+fAYOHPhEtVoWbL/C39dzEyCp1SKEEOVTmRapS0tL4+LFi1y4cIGLFy/yxRdflNWuy4wUqSt9iqKwZcsWpk2bRmBgIABubm7Mnj0bf39/1Gp1sfoLuZ3EJzuC2HEpBpBaLUIIoS96KVJ38+ZNLly4gLOzM61atcq33MLCgpYtW9KyZUtd7lZUIvv372fKlCkcP34cAAcHB6ZNm8Ybb7yhk1otzzavyQSp1SKEEOWazpKX9evXM2LECLKyslCpVDRr1oy//vqLatWq6WoXohI7e/YsU6dOZceOHQBYWVkxceJEJk2apJNaLT0bODNZarUIIYRB0NltIx8fHzp06MD7779PeHg477zzDo0bN2blypW66N5gyG0j3QoJCWH69Ols2LABABMTE1577TU++OADnJ2di9WX1GoRQojyraifoTpLXkxNTQkODtbO3hwUFETz5s1JSUnRRfcGQ5IX3YiKimLOnDksX76c7OxsVCoVL730ErNnz6Z27drF6ktqtQghhGEo8zEv2dnZWFj8N07A29sbjUZDdHR0sauZisorPj6ejz/+mC+//JK0tDQAnn76aebPn0/Tpk2L1VdBtVrc7S2Z1LOe1GoRQggDptMBu2vWrKF9+/Y0adKEKlWqYGxsrC0WJsSjpKWlsWjRIgICAoiLiwOgbdu2fPTRR3Tq1KlYfRVWq2V8dy+GtJRaLUIIYeh0lrx06NCBuXPnkpSUhJGREZ6enqSnp7Ny5Up69OiBn5+f3EYR+WRnZ7N69WpmzpzJrVu3AGjYsCHz58+nf//+xb6lcyYsjo8fqtXyWqfavCq1WoQQosLQeZ2X4OBgTp8+zZkzZzh9+jRnz54lPj4eIyMjvLy8tHU5KioZ81I0iqKwadMmpk2bRlBQEADu7u7Mnj2bl19+WSe1Wl5p68GbUqtFCCEMhl7qvAB4eXnh5eXFkCFDtG2hoaGcOnWKs2fP6np3wgDt3buXKVOmcPLkSQAcHR2ZNm0ar7/++hPVavly91V+OR0htVqEEKKSKPGVl7S0NO7du0eNGjXytF+6dImGDRuWKDhDJFdeCnf69GmmTp3Krl27gNxaLZMmTWLSpEnF/n8Vl5LJkv0hrDl2U2q1CCFEBVEmV15++eUX3n77bezt7VEUheXLl9O6dWsA/P39OXPmTEm6FxVEcHAwH3zwAT/99BOQW6vljTfeYNq0aTg5ORWrr9TMbFYdDuXbA9elVosQQlRSJUpe5s6dy5kzZ6hWrRqnTp1i+PDhTJs2TTt7tKjcIiMjmT17NitWrCAnJweVSsXLL7/MrFmz8PT0LFZfWTkaNpwI46s9IdxNllotQghRmZUoecnKytKW/2/RogUHDx7kmWeeISQkRD5MKrG4uDg+/vhjvvrqK22tlr59+zJ//nyaNGlSrL40GoVtFyL5fNdVqdUihBACKGHy4uTkxIULF7QfSA4ODuzatYvhw4dz4cIFnQQoDEdqaiqLFi3io48+0tZqad++PQEBAXTs2LFYfSmKwoGrd/h4exCXo+7XajHj/7rX5UWp1SKEEJVaiZKXOXPm5JtfxtTUlPXr1zNu3LgSBSYMR3Z2NqtWrWLWrFlERkYC0KhRI+bPn0+/fv1KXKvF2syYsVKrRQghxL9K9Enw1VdfcePGDVq2bEnPnj3p3r071ta5T3q0b99eJwGK8ktRFH799VemTZvG1atXAfDw8GD27NkMGzas5LVajI14pY3UahFCCJFXiR+V1mg0nDx5kp07d7J3715UKhVdu3alZ8+etGrVqtKNfaksj0rv3r2bqVOncurUKQCqVavGBx98wGuvvYaZmVmx+pJaLUIIIUAPs0rfl5SUxJ49e9i5cyenTp3ixIkTuuy+3KvoycupU6eYOnUqu3fvBqBKlSpMnjyZiRMnaq+6FVVhtVre6eWNl9RqEUKISqfMKuzGxcWhKAr29vbcuXOHgwcP4u3tzaBBg0ratShHrl69ygcffMDPP/8M5I5teuONN3j//fd1Uqultac97/Xxobm71GoRQgjxaCVKXlasWEFAQAAajYZ3332XtWvX0qRJE2bMmMH48eMZO3asruIUenLr1i1mz57NypUrtbVa/P39mTVrFrVq1SpWX5nZGjaezF+r5b3e3nSWWi1CCCGKqETJy8KFC7l06RKpqam4u7sTGhpKtWrVSExMpFOnTpK8GLC4uDg++ugjvv76a9LT0wHo378/8+fPp1GjRsXq636tls92XiXsntRqEUIIUTIlSl7UajXm5uaYm5tTt25dbcG6qlWryrdoA5WamsrXX3/NggULiI+PB6BDhw589NFHxX6CTGq1CCGEKA0lSl6MjY1JT0/H3NycAwcOaNuTkpJKHJgoW1lZWdpaLVFRUQA0btyYgIAAnn766Seq1bLgryscD/2vVstrnXNrtViaSq0WIYQQT65EnyJ79+7VPhZrY2OjbU9LS2PlypUli0xPkpKS6NatG1lZWeTk5DB+/HjGjBmj77BKjUaj4ZdffuGDDz4gODgYgFq1ajFnzhyGDh36RLVaPt4exM7L/9VqGd7Wgze71MVOarUIIYTQAZ0/Kh0TE5Ov6q4hycnJISMjA0tLS1JTU2nUqBEnT57EwcGhSNsbyqPSiqJoa7WcPn0ayK3VMn36dMaOHftEtVq+2HWVX8/8V6vlOb+a/F8PqdUihBCiaMrsUemHPfvss+zfvx9j4/xdZ2dnF9henqjVaiwtLQFIT08nJyenws2QffLkSaZMmcLevXsBsLa2ZvLkybz99ts6qdXSq6Ezk3tKrRYhhBClQ+cjJu3s7HjrrbfytcfGxtKjR48S93/w4EH69++Pq6srKpWKLVu25FtnyZIleHp6Ym5ujp+fH4cOHSrWPuLj42natCk1a9bk3XffxdHRscRxlwdBQUE899xztGrVir1792JqasqECRO4du0aH374YbESl9TMbBbtDabTx/tYfiiUzGwNrT3t2fRmO771byGJixBCiFKj8+Tlhx9+YM+ePaxYsULbFhgYSKtWrXRyGyUlJYWmTZuyaNGiApdv3LiRCRMmMG3aNM6ePUvHjh3p06cPYWFh2nX8/Pxo1KhRvtf9SQVtbW05f/48oaGhrFu3jpiYmBLHrU8RERGMGTOGhg0b8uuvv2JkZMSIESO4evUqX3zxhfYpsaLIzNbww7EbdPp4P5/uvEpSRjYNqldl9ciWbBjbRorMCSGEKHU6H/MC8M8//9C5c2f++usv4uLiGDJkCGPHjmXBggU6fYRapVKxefPmPNV8W7duTfPmzVm6dKm2rX79+gwaNIiAgIBi7+ONN96gW7duPP/88wUuz8jIICMjQ/s+MTERNze3cjHm5d69e3z00UcsXLhQW6tl4MCBzJs3j4YNGxarL6nVIoQQorSV6ZiXgQMH4uvrS7NmzfD19aVx48YsXryYvn37kp6ezuLFixk+fLgudvVImZmZnD59milTpuRp79mzJ0ePHi1SHzExMVhYWFC1alUSExM5ePAgb7zxRqHrBwQEMGvWrBLFrWspKSnaWi0JCQkAdOzYkY8++oh27doVqy+p1SKEEKK80Uny4uXlxZEjR1iyZAmxsbHY2trStGlTFEVh2LBh+Pr6kpWVhYmJiS52V6i7d++Sk5OT72knZ2dnoqOji9RHREQEo0aNQlEUFEVh3LhxNGnSpND1p06dysSJE7Xv71950YesrCxWrlzJrFmztMfbtGlTAgIC6N27t9RqEUIIUSHo5BPo008/1f4cERHBuXPnOHfuHA4ODtrxL8bGxvj4+HD+/Hld7PKRHv6QVhSlyB/cfn5+nDt3rsj7MjMzK/Zjxbqm0Wj46aef+OCDD7h27RoAnp6ezJ07lyFDhmBkVLyrI1KrRQghRHmm86/PNWvWpGbNmvTr10/blpyczNmzZ7lw4YKud5eHo6MjarU631WW27dvG3TtmcIoisLOnTuZOnUqZ8+eBcDJyYkPP/yQMWPGYGpavESjsFotE3rUw1VqtQghhCgnyuTaf5UqVejYsSMdO3Ys1f2Ympri5+fHrl27GDx4sLZ9165dDBw4sFT3XdaOHz/OlClT2L9/P5Bbq+Xdd99lwoQJVKlSpVh9xaVksnhfCN//nbdWyzu9vKnrJI88CyGEKF8MbuBCcnIyISEh2vehoaGcO3cOe3t73N3dmThxIv7+/rRo0YK2bduybNkywsLCeP311/UYte4EBgYybdo0Nm/eDOQmbOPGjWPq1KnFrkeTkpHNqsOhLDt4naSMbADa1Lbnvd4+NJNHnoUQQpRTBpe8nDp1iq5du2rf3x8sO3z4cFavXs2LL75IbGwss2fPJioqikaNGvHnn3/i4eGhr5B1Ijw8nJkzZ7J69Wo0Gg1GRkYMHz6cmTNn4u7uXqy+MrM1bDgZxtd7QribnPuYd4PqVXmvjw+dvBxlRnAhhBDlWqnUeanMdD23UVxcHPPmzWPRokXaejKDBg1i3rx5NGjQoFh9FVSrxcPBkkk9venXuLrUahFCCKFXepvbSOhWamoqixcvJiMjg86dO/PRRx/Rpk2bYvWhKAr7/63VEvhgrZYeXrzYwk1qtQghhDAokryUczVq1ODzzz/H09OTXr166aRWy+td6jCyfS2p1SKEEMIgyaeXAXhUhd/CBMck8ckOqdUihBCi4pHkpYK5FZ/Gl1KrRQghRAUmyUsFUVCtlt4NXZjcq57UahFCCFGhSPJi4KRWixBCiMpGkhcDVVCtloauVXm3t9RqEUIIUbFJ8mJgpFaLEEKIyk6SFwNRUK2WatZmjO/uxZCWbpiopVaLEEKIykGSFwMgtVqEEEKI/8gnXzl3NSaJZ5YcBXJrtYxoV4s3OteRWi1CCCEqLUleyrl6ztb0qO+Mg5Up/9fDS2q1CCGEqPQkeTEA3/r7oZaBuEIIIQQAMsrTAEjiIoQQQvxHkhchhBBCGBRJXoQQQghhUCR5EUIIIYRBkQG7OpaTkwNAREQEVatW1XM0QgghhOFITMwtwnr/s7QwkrzoWEhICAANGzbUcyRCCCGEYQoJCaFly5aFLlcpiqKUYTwVXlxcHPb29oSHh8uVFyGEEKIYEhMTcXNz4969e9jZ2RW6nlx50TG1Wg1A1apVJXkRQgghnsD9z9LCGPSA3SVLluDp6Ym5uTl+fn4cOnTokesfOHAAPz8/zM3NqV27Nt98802+dX799VcaNGiAmZkZDRo0YPPmzaUVvhBCCCGegMEmLxs3bmTChAlMmzaNs2fP0rFjR/r06UNYWFiB64eGhvL000/TsWNHzp49y/vvv8/48eP59ddftescO3aMF198EX9/f86fP4+/vz8vvPACx48fL6vDEkIIIcRjGOyYl9atW9O8eXOWLl2qbatfvz6DBg0iICAg3/rvvfceW7duJTAwUNv2+uuvc/78eY4dOwbAiy++SGJiIn/99Zd2nd69e2NnZ8f69euLFFdiYiI2NjYkJCTIbSMhhBCiGIr6GWqQY14yMzM5ffo0U6ZMydPes2dPjh49WuA2x44do2fPnnnaevXqxcqVK8nKysLExIRjx47x9ttv51vnyy+/LDSWjIwMMjIytO/vP+alaw/vx8TEBAsLC9LS0sjKytK2m5mZYWZmRkpKSp5HzczNzTE1NSU5ORmNRqNtt7S0xNjYOF/cVlZWGBkZkZSUlKfd2toajUZDSkpKnvaqVauSnZ1Namqqts3IyIgqVaqQmZlJenq6tl2tVmNlZSXHJMckxyTHJMdUAY5JLxQDdOvWLQVQjhw5kqd93rx5Sr169QrcxsvLS5k3b16etiNHjiiAEhkZqSiKopiYmChr167Ns87atWsVU1PTQmOZMWOGAuR7JSQkPMmhFXk/o0aNUhRFUUaNGpWnfcaMGYqiKErPnj3ztC9fvlxRFEVp0KBBnvbt27criqIo1tbWedovXryoJCQkFHhcFy9ezNNmbW2tKIqibN++PU97gwYNFEVRlOXLl+dp79mzpxyTHJMckxyTHFMFOSZduh/r4z5DDfK2UWRkJDVq1ODo0aO0bdtW2z5v3jx++OEHrly5km+bevXqMXLkSKZOnaptO3LkCB06dCAqKgoXFxdMTU1Zs2YNQ4cO1a6zdu1aRo0alSfbfFBBV17c3Nx0ftuoImbrckxyTHJMckxyTIZ/TLpUoW8bOTo6olariY6OztN++/ZtnJ2dC9zGxcWlwPWNjY1xcHB45DqF9Qn//QUrbYXtx8LCAgsLi3zthf2FqlKlSoHthf0lKahdrVYX2G5sbFxgu6mpKaampvna5ZjkmAqLvbB2OSY5JpBjgvJ1TPpgkE8bmZqa4ufnx65du/K079q1i3bt2hW4Tdu2bfOtv3PnTlq0aIGJickj1ymsTyGEEEKUPYO88gIwceJE/P39adGiBW3btmXZsmWEhYXx+uuvAzB16lRu3brF999/D+Q+WbRo0SImTpzImDFjOHbsGCtXrszzFNH//d//0alTJxYsWMDAgQP57bff2L17N4cPH9bLMQohhBAiP4NNXl588UViY2OZPXs2UVFRNGrUiD///BMPDw8AoqKi8tR88fT05M8//+Ttt99m8eLFuLq68vXXX/Pss89q12nXrh0bNmzggw8+YPr06dSpU4eNGzfSunXrMj8+IYQQQhTMIAfslmdS50UIIYR4MkX9DDXIMS9CCCGEqLwkeRFCCCGEQZHkRQghhBAGRZIXIYQQQhgUSV6EEEIIYVAkeRFCCCGEQZHkRQghhBAGRZIXIYQQQhgUSV6EEEIIYVAkeRFCCCGEQZHkRQghhBAGRZIXIYQQQhgUSV6EEEIIYVAkeRFCCCGEQZHkRQghhBAGRZIXIYQQQhgUSV6EEEIIYVAkeRFCCCGEQZHkRQghhBAGRZIXIYQQQhgUSV6EEEIIYVAkeRFCCCGEQZHkRQghhBAGRZIXIYQQQhgUg0xe4uLi8Pf3x8bGBhsbG/z9/YmPjy90/aysLN577z0aN26MlZUVrq6uvPLKK0RGRuZZr0uXLqhUqjyvIUOGlPLRCCGEEKI4DDJ5eemllzh37hzbt29n+/btnDt3Dn9//0LXT01N5cyZM0yfPp0zZ86wadMmrl69yoABA/KtO2bMGKKiorSvb7/9tjQPRQghhBDFZFySjWfPnv3I5R9++GFJui9QYGAg27dv5++//6Z169YALF++nLZt2xIUFIS3t3e+bWxsbNi1a1eetoULF9KqVSvCwsJwd3fXtltaWuLi4qLzuIUQQgihGyW68jJ79mw2bdoEgKOjIw4ODnlepeHYsWPY2NhoExeANm3aYGNjw9GjR4vcT0JCAiqVCltb2zzta9euxdHRkYYNGzJ58mSSkpIe2U9GRgaJiYl5XkIIIYQoPSW68hIREcEvv/zC5s2bMTU15fnnn2fw4MHY2dnpKr58oqOjcXJyytfu5OREdHR0kfpIT09nypQpvPTSS1StWlXbPmzYMDw9PXFxceHixYtMnTqV8+fP57tq86CAgABmzZpV/AMRQogypigKt5MyiIxPQ22kwsPBChsLE32HJUSxlSh5cXFxYdy4cYwbN46oqCg2bNhA/fr1WbBgAcOHDy9WXzNnznxsEnDy5EkAVCpVvmWKohTY/rCsrCyGDBmCRqNhyZIleZaNGTNG+3OjRo3w8vKiRYsWnDlzhubNmxfY39SpU5k4caL2fWJiIm5ubo+NQwghykpwTBLrToSx/WI0UQnpeZY1rmHDsNbuPOdXE2O1QQ6DFJVQiZIXyE0aDhw4wMaNGzlx4gRDhw6lffv2xe5n3Lhxj32yp1atWly4cIGYmJh8y+7cuYOzs/Mjt8/KyuKFF14gNDSUvXv35rnqUpDmzZtjYmJCcHBwocmLmZkZZmZmj+xHCCH0IfxeKh/9dYU/L0ahKLltaiMVLlXNycrRcDspg39uJTBl0z+sPnqDr4Y0w9vFWr9BC1EEJUpexo0bx99//03Hjh155ZVXWLp06RP35ejoiKOj42PXa9u2LQkJCZw4cYJWrVoBcPz4cRISEmjXrl2h291PXIKDg9m3b1+RxuRcunSJrKwsqlevXvQDEUIIPcvRKHx3JJTPdl4lLSsHgF4NnXnOz42OXo6Ym6gBuJucwaYzESzZf40r0Uk8s+QIi4Y1p6t3/lvzQpQnKkW5n48Xn5GREfb29trbNff/vH8L5/bt27qJ8iF9+vQhMjJS+xjz2LFj8fDwYNu2bdp1fHx8CAgIYPDgwWRnZ/Pss89y5swZfv/99zxXaOzt7TE1NeXatWusXbuWp59+GkdHRy5fvsykSZOwsLDg5MmTqNXqIsWWmJiIjY0NCQkJj72yI4QQunY3OYP/23CWIyGxALTytGf2wIb4uBT++yg2OYO31p/l6LVYTI2N+G5ES9rXffyXSSF0raifoSVKXvTl3r17jB8/nq1btwIwYMAAFi1alOfJIZVKxXfffceIESO4ceMGnp6eBfa1b98+unTpQnh4OC+//DIXL14kOTkZNzc3+vbty4wZM7C3ty9ybJK8CCH05dSNe/xv3RliEjOwMFHzYf8GvNjCDSOjIowHzNEwbt0ZdlyKwcpUzW/jOlDXqUoZRC3Ef8oseVmxYgVLliwhKCgIyL3i8dZbbzFixIiSdGuwJHkRQujD7xcimbjxPJk5GupUs+Kbl/3wci7e+JWM7Bz8V57gROg96jpVYeu49lialnhopBBFVtTP0BINLV+xYgVLly7l888/JyoqisjISD777DMWL17Md999V5KuhRBCFNF3R0J5a/1ZMnM09G7owtZxHYqduACYGatZ/FJznKuaEXI7mU93XC2FaIUouRJdeWnZsiWbNm3K92hweHg4zzzzjPbR5spErrwIIcqKoigs2B7ENweuAfBKWw9m9G+Iugi3iR7lwNU7DF91ApUKNr3RjmbupVe7S4gHlcmVl9TU1AJrmri5uZGamlqSroUQQjxCVo6GST+f1yYu7/TyZtaAkicuAJ3rVeOZZjVQFJjy6z9k52hK3KcQulSi5MXc3LzQZVL7RAghSkdKRjaj1pxi05lbqI1UfPJcE/7XtW6RCnUW1fR+DbC1NCEoJolfTkforF8hdKFEI7HOnz9fYKl+RVFISEgoSddCCCEKcDc5g1dXn+RCRAIWJmqWDGtOVx/d12WxszLlrW5ezPn9Ml/svsoAX1cZvCvKjRL9TczOztZVHEIIIR4jLDaVV1Yd50ZsKvZWpqwa0RJfN9tS29/Lbdz57kgoEXFpfHfkBv/rWrfU9iVEcZTotlFCQgI3btzI137jxg2ZXVkIIXTo4q0Enll6hBuxqdS0s+CX19uWauICuU8fTe7pDcCKQ9dJzZQvrKJ8KFHyMm7cOEJCQvK1X7x4kbfeeqskXQshhPjXwat3ePHbY9xNzqRB9apserMdtauVTQG5fk2q4+FgSVxqFutPhJfJPoV4nBIlL2fPnqVHjx752vv168eZM2dK0rUQQgjgl9MRvLr6JCmZObSr48DG19rgZF34wxK6Zqw24vXOdQBYfvA6mdny5JHQvxIlL+np6YUuy8jIKEnXQghRqSmKwsI9wUz++TzZGoVBvq6sHtkKa3OTMo/lmeY1cK5qRnRiOpvPypNHQv9KlLw0btyYtWvX5mtft24d9evXL0nXQghRaWXnaHh/8z98tiu3wu0bXerw+Qu+mBqX6Ff2EzMzVjO6Q20Alh28jgFOiScqmBJV2I2IiGDw4MFUrVoVX19fVCoVZ86cITExkS1btlCzZk1dxmoQpMKuEKIkEtOzGL/+LPuD7mCkglkDGuLftpa+wyIpPYs28/eQkpnD2tGtZdZpUSqK+hlaokela9asycmTJ9mzZw+XL19GURR69+5d4DgYIYQQj3b9TjJjvj/FtTspmJsY8fWQZvRs6KLvsACwNjfhWb+afH/sJt8fuyHJi9CrEs8qXZDY2Fh+/fVXxo4dq+uuyz258iKEeBIHr95h3LozJKZnU93GnGX+LWhc00bfYeURHJPEU18cxEgFh97rRg1bC32HJCqYMpnb6EFxcXGsWrWKnj170qxZMy5cuKCrroUQosJSFIUVh64z4rsTJKZn4+dhx2/j2pe7xAXAy9madnUc0Ciw9u+b+g5HVGIlSl4SExNZs2YNTz/9NK1ateLSpUvMmDGDmzdvsmjRIl3FKIQQFVJCWhZv/HiGuX8EolHghRY1WTemdZk+Cl1cr/w7/mbDyXDSs3L0G4yotEo05sXJyYnu3bszZ84c/Pz8dBWTEEJUeBci4vnfujOE30vDRK3ig74NeKWth04nVywNPeo74WpjTmRCOtsvRjOoWQ19hyQqoRJdeVm0aBHZ2dm8/PLLTJkyhRMnTugqLiGEqJA0GoVVh0N5dulRwu+l4WZvwS+vt2N4u1rlPnGB3KJ1L7Z0B2DDyTA9RyMqK50M2L0/QHfjxo1cv36dAQMG8Mwzz9C5c2ddxGhQZMCuEKIwEXGpvPvLBY5eiwWgTyMXPnq2CTYWZV94riQi49Nov2AvigL7J3ehlqOVvkMSFUSZDth1cHBg7Nix7Nmzh+PHj+Pt7c3MmTN10bUQQhg8RVH46VQ4vb88xNFrsViYqJkzqBFLhjU3uMQFwNXWgs71qgHw0ymZ70iUvVJ5VLoykysvQogHhcWm8uHWi+wPugOAn4cdnz3f1OCvVmy/GMXrP56hmrUZx6Z0w1itn+q/omIpkyJ1QgghCpaZrWH5oet8vSeYjGwNpmojJvasx5iOtVEblf+xLY/TzccZBytT7iRlsC/oDk81cNZ3SKISKZVUOSoqSiZmFEJUWseuxfL014f4ZEcQGdka2tZ24M//68jrnetUiMQFwNTYiGf9cqeA2SgDd0UZK5Xkxd/fHx8fHyZPnlwa3QshRLl07d/y/kOX/03I7WQcq5jy5Yu+rBvTmrpOVfQdns690MINgL1XbhOdkK7naERlUirJy+7duwkNDWX06NGl0T1xcXH4+/tjY2ODjY0N/v7+xMfHP3KbESNGoFKp8rzatGmTZ52MjAzeeustHB0dsbKyYsCAAUREyPTvQohHu5ucwfQtF+n5xUF2XY5BbaTCv40HeyZ2YVCzGgbxCPSTqOtUhZa17NAo8OsZ+V0pyo5OkpfvvvuuwHYfHx9ddJ/PSy+9xLlz59i+fTvbt2/n3Llz+Pv7P3a73r17ExUVpX39+eefeZZPmDCBzZs3s2HDBg4fPkxycjL9+vUjJ0eqSAoh8otLyeSTHVfo8sl+fvj7JjkahR71ndkxoRNzBjXCxtLwniQqrvs1XzaeDEejkec/RNnQyYDdTZs2UatWLbp27QpAWloao0ePZu3atbroPo/AwEC2b9/O33//TevWrQFYvnw5bdu2JSgoCG9v70K3NTMzw8Wl4BlaExISWLlyJT/88IN2Vuwff/wRNzc3du/eTa9evXR+LEIIwxSbnMHyQ6H8cOwGKZm5X24a17Dh/afr07aOg56jK1tPN3Zh5tZLhN1L5e/rsbST2aZFGdDJlZcff/yRadOmceXKFYKDg+nYsSNdunTRRdf5HDt2DBsbG23iAtCmTRtsbGw4evToI7fdv38/Tk5O1KtXjzFjxnD79m3tstOnT5OVlUXPnj21ba6urjRq1OiR/WZkZJCYmJjnJYSomCLiUpn7+2U6fryPbw5cIyUzh4auVVnm78fWce0rXeICYGlqzABfVwDWn5SaL6JslOjKy8SJE/H19cXX15dVq1bx0ksvoSgKq1atolmzZrqKMY/o6GicnJzytTs5OREdHV3odn369OH555/Hw8OD0NBQpk+fTrdu3Th9+jRmZmZER0djamqKnZ1dnu2cnZ0f2W9AQACzZs168gMSQpR7Z8LiWHkolO2Xosn599ZI4xo2/F93L7rXd6qwY1qKamhLd9YdD2PHxWjupWRib2Wq75BEBVei5KVz585cuHCBbdu2ceXKFSIjI2nTpg07d+4kMjKSvn37FrmvmTNnPjYJOHnyJECBvygURXnkL5AXX3xR+3OjRo1o0aIFHh4e/PHHHzzzzDOFbve4fqdOncrEiRO17xMTE3Fzc3vkcQghyr/0rBz+/CeKH/6+ydmweG17+7oOjO5Qmy7e1Sp90nJf45o2NKpRlYu3Etl0JoLRHWvrOyRRwRU7ebl58yYXLlzA2dmZgQMHMnDgQO2ytLQ0Ll68yIULF9i9e3exkpdx48YxZMiQR65Tq1YtLly4QExMTL5ld+7cwdm56EWSqlevjoeHB8HBwQC4uLiQmZlJXFxcnqsvt2/fpl27doX2Y2ZmhpmZWZH3K4Qo3wKjEtlwIozNZ2+RmJ4NgKnaiIG+rrzawZP61aVydkGGtnJn2uaLrDsRxqgOnpLYiVJVrORl/fr1jBgxgqysLFQqFc2aNeOvv/6iWrXcOS4sLCxo2bIlLVu2LHYgjo6OODo+fqBX27ZtSUhI4MSJE7Rq1QqA48ePk5CQ8Mgk42GxsbGEh4dTvXp1APz8/DAxMWHXrl288MILQG6xvYsXL/Lxxx8X+3iEEIbjXkomf/wTxS+nIzgfHq9tr2FrwYst3Rjayp1q1vIl5VEG+tZg3h+BXL+TwonQe7SuXfnG/4iyU6y5jXx8fOjQoQPvv/8+4eHhvPPOOzRu3JiVK1eWZoz59OnTh8jISL799lsAxo4di4eHB9u2bcsTa0BAAIMHDyY5OZmZM2fy7LPPUr16dW7cuMH7779PWFgYgYGBWFtbA/DGG2/w+++/s3r1auzt7Zk8eTKxsbGcPn0atVpdpNhkbiMhDENyRja7Lkfz27lIDgffJfvfsSzGRiqeauDMkFbudKzriFEFqYhbFqZuusD6E+EM8nXlyyGlM+5RVGylMrfR9evX2bFjBx4eHtSuXZsffviB5s2bl3nysnbtWsaPH699MmjAgAEsWrQozzpBQUEkJCQAoFar+eeff/j++++Jj4+nevXqdO3alY0bN2oTF4AvvvgCY2NjXnjhBdLS0ujevTurV68ucuIihCjfEtKy2B90m52XYthzJYb0LI12WaMaVRnYtAaDmtWQqyxPaGgrd9afCOfPi9HMSMnETgbuilJSrCsvRkZG+Z72sbCwIDQ0tND6KZWNXHkRony5FZ/GrkvR7AqM4fj1e9orLACejlYMaOrKAF9X6lSreOX7y5qiKPRbeJhLkYlM79eAUR089R2SMDClNqv0mjVraN++PU2aNKFKlSoYGxuTmppaomCFEEJX0rNyOHnjHoeC73Lw6h2uRCflWe7lVIWnGjjTu5ELjWvYyMBSHVKpVAxt5c4HWy6y/kQYr7avJf9/RakoVvLSoUMH5s6dS1JSEkZGRnh6epKens7KlSvp0aMHfn5+crVBCFGmcjQKV6ITORx8l0PBdzlx4x6Z2f/dDjJSQQsPe55q4MxTDZyp5Wilx2grvoG+rsz7I5CQ28mcuhlHy1r2+g5JVEDFum10X3BwMKdPn+bMmTOcPn2as2fPEh8fj5GREV5eXgQGBpZGrAZBbhsJUbrSs3K4EJHAyRv3OHnjHqdvxpH07yPN97lUNaejlyMdvBzp6FVNiqaVsfd+ucDGU+E806wGn7/oq+9whAEptdtGAF5eXnh5eeWpyxIaGsqpU6c4e/bsk3QphBD5KIpCRFwa/9xK4HxEPKdvxHEhIoHMHE2e9axM1bSu7UBHL0c6ejlSp1oVuV2hRy+1dmfjqXB+vxDF1KfrywBooXPFuvLy/vvvM2jQIG19FZGfXHkR4skoikJ0Yjr/RCT8m6wk8E9EPHGpWfnWdaxiRitPO1p42NPK0x4fF2uM1TqZqk3oyOAlRzgbFs+EHl5M6FFP3+EIA1EqV16ioqLo168farWa/v37M3DgQHr06CEVZoUQxZKQmkVQTBJBMUlcjU4iKDr354S0/ImKsZEKn+rWNKlpi6+bLa1q2ePhYClXVsq5V9t78lbYWX78+yZvdKmDmbGUnBC6U6zk5bvvvkNRFA4fPsy2bduYNGkSt27d4qmnnmLAgAH069evSFVyhRAVX45G4VZcGqGxKYTeSeZGbCrX76ZwNTqJ6MT0ArcxUkE9Z2sa17ChSU0bmtS0xdvFGnMT+eAzNL0buVDdxpyohHS2nY/iOb+a+g5JVCBPNGD3QYGBgWzbto3ffvuNU6dO0bp1awYMGMDQoUOpUaOGruI0GHLbSFQmCWlZRMancSsujciENMJiU7kRm8L1uymE30slK6fwXy+uNuZ4u1hTz8UaHxdr6jlbU6daFUlUKpCl+6+xYPsVGlSvyh/jO8jVMvFYRf0MLXHy8qA7d+6wdetWtm7dSseOHZk8ebKuujYYkryIikBRFOJSs7iTlMGdpAxuJ6UTk5jBrfhUIuPTc5OV+DSSMrIf2Y+psREe9pZ4Olrh6WhFLUcr6jlXwcvZmqrmJmV0NEJf4lMzaROwh/QsDRvGtqGNzHckHqNMk5fvvvuOkSNHlrSbCkGSF1EeaTQKSRnZxKdmEpeaRVxqJgn//hmXksmd5IwHEpUM7iZnPPKqyYPsLE2oYWeBq40FNe0s8axmhaeDFbUcLaluY4Fa5gaq1N7f/A/rjofRo74zK4a30Hc4opwr1UelH7Zp0yZq1apF165dAUhLS2P06NGsXbtWF90LUall52hIzcohJSOb5PRskjKytT8nZ/z7Ss8mOfOBtvRs4tNyk5P41CwS0rLI0RT/e4qtpQlO1mZUszbDydqcGrYWuNpaUMPOghq25rjaWmBpqpNfI6KCerW9J+tPhLE7MIYr0Yn4uMiXOlFyOvmt8+OPP9KnTx9WrVqFWq1m6NChvPbaa7roWgidUxQFjQIaRSFHo6AokKMoaBQFjSa37cHl2TkKWRoNWTma3J9zNGTlKGTnaMh8sE2T23Z/uXZ9jYas7Nz36Vk5pGfnkJ71789ZD/z8b3taZg4ZD6yT/QRJR2EsTdXYWphga2mKnZUJtham2FqaUO2BBCX3TzMcqpjKEyKixOo6VaFPIxf+/CeaJfuu8fVQmW1alFyJbhtNnDgRX19ffH19MTU15aWXXkJRFFatWkWzZpXzL6iubxspisLI1Se5f5aUB9rzrnd/uZL3fWHt2g0fvfz+fv57//D2hS0vLI788T8uxodj4N/EQqPwb/Kh/Jt85N4eKTgp+TcZURSe/G+8fhkbqahibkwVswdej3hva/lvkmKZm6DYWJjIYFihF5ciE+j79WGMVLB3UheZokEUqkxuG3Xu3JkLFy6wbds2rly5QmRkJG3atGHnzp1ERkbSt2/fknQv/rU/6I6+Q6iU1EYqjFRgojbC2EiFqbERxkZGmBirMDEywlityl2mNsJUrfp3mREmRirtstyXCmN1bru5qRpzYzXmJmrMTYy0f1qYqDEzub/sfrsaiwfWMzM2kqc1hEFq6GpDNx8n9l65nfsE0nNN9B2SMHDFvvJy8+ZNLly4gLOzc75Ku2lpaVy8eJELFy5w8eJFvvjiC50GawhK48rLL6cjtB9a9z+67n+Gaf/8d8nDn22FbvfQ+g8vp9DlRYuDom5XyH54zHIjIxVGqtzkQq39WYWREahVKu1ytUqF6sF1jNC2a9d/cPt/15UkQQjdOn0zjmeXHsVErWL/O12pYWuh75BEOVQqTxutX7+eESNGkJWVhUqlolmzZvz1119Uq1ZNJ0FXBPK0kRBCFOyl5X9z9FosL7Zwk6svokBF/Qwt1mQgs2bNwt/fn5CQEPbu3YuRkRFTpkwpcbBCCCEqvsm9vAH4+XQ4IbeT9RyNMGTFuvJiampKcHAwHh4eAAQFBdG8eXNSUlJKLUBDI1dehBCicGO+P8WuyzH0aeTC0pf99B2OKGdK5cpLdnY2Fhb/3af09vZGo9EQHR395JEKIYSoNN7p5Y1KBX9djOZ8eLy+wxEGqthzyK9Zs4ajR4+SnJx7yc/Y2JjU1FSdByaEEKLiqedszeBmufPefbIjSM/RCENVrOSlQ4cOzJ07lw4dOmBra4uXlxfp6emsXLmSffv2kZiYWFpxCiGEqCDe7lEPE7WKwyF3OXhVSkGI4nuiInXBwcGcPn2aM2fOcPr0ac6ePUt8fDxGRkZ4eXkRGBhYGrEaBBnzIoQQjzfn98usPBxKPecq/Dm+I8bqYt8IEBVQqRap8/LywsvLiyFDhmjbQkNDOX36NN99992TdCmEEKISGd/Ni01nIrgak8y6E2G80raWvkMSBkQnqW5CQgJ//fUX8+fPZ/v27broUgghRAVmY2nCxKfqAfD5rqvEp2bqOSJhSEqUvOzdu5eXX34ZFxcXZs2ahaenp67ieqS4uDj8/f2xsbHBxsYGf39/4uPjH7mNSqUq8PXJJ59o1+nSpUu+5Q9eXRJCCKE7Q1u54+1sTXxqFl/uDtZ3OMKAFDt5iYiIYO7cudSpU4cBAwagKAq//vorkZGRzJo1qzRizOell17i3LlzbN++ne3bt3Pu3Dn8/f0fuU1UVFSe16pVq1CpVDz77LN51hszZkye9b799tvSPBQhhKi0jNVGfNCvPgA//H2TkNtJeo5IGIpijXl5+umn2bdvH926dWP27NkMGjQIK6v/Zgcti/lgAgMD2b59O3///TetW7cGYPny5bRt25agoCC8vb0L3M7FxSXP+99++42uXbtSu3btPO2Wlpb51hVCCFE6OnpVo0d9J3YH3mbuH4GsHtnq8RuJSq9YV162b9/Os88+y6xZsxg2bFiexKWsHDt2DBsbG23iAtCmTRtsbGw4evRokfqIiYnhjz/+YNSoUfmWrV27FkdHRxo2bMjkyZNJSnr0N4GMjAwSExPzvIQQQhTdtL4NcidsDLrDnsAYfYcjDECxkpcjR45gYWFBt27d8Pb2Zvbs2YSEhJRWbAWKjo7GyckpX7uTk1ORK/2uWbMGa2trnnnmmTztw4YNY/369ezfv5/p06fz66+/5lvnYQEBAdqxNzY2Nri5uRX9YIQQQuDpaMWrHXLHTM7adpn0rBw9RyTKu2IlL23btmX58uVER0fz3nvvsXPnTry9vWnTpg0LFy4kJubJM+aZM2cWOqj2/uvUqVNAwbenFEUp8m2rVatWMWzYMMzNzfO0jxkzhh49etCoUSOGDBnCL7/8wu7duzlz5kyhfU2dOpWEhATtKzw8vBhHLYQQAnIfnXauakbYvVSWHbyu73BEOfdEdV4sLS159dVXefXVVwkKCmLlypXMnz+fmJiYJx73Mm7cuMc+2VOrVi0uXLhQYJJ0584dnJ2dH7ufQ4cOERQUxMaNGx+7bvPmzTExMSE4OJjmzZsXuI6ZmRlmZmaP7UsIIUThrMyMmda3AePXn2XxvhAGN6uBm72lvsMS5dQTJS8P8vb25uOPPyYgIIBt27axatWqJ+rH0dERR0fHx67Xtm1bEhISOHHiBK1a5Q7sOn78OAkJCbRr1+6x269cuRI/Pz+aNm362HUvXbpEVlYW1atXf/wBCCGEKJH+Taqz7vhN/r5+j7l/XOZb/xb6DkmUU080PYC+9enTh8jISO1jzGPHjsXDw4Nt27Zp1/Hx8SEgIIDBgwdr2xITE6levTqfffYZr7/+ep4+r127xtq1a3n66adxdHTk8uXLTJo0CQsLC06ePIlarS5SbDI9gBBCPLmg6CSe/voQORqFNa+2onO9avoOSZShon6GGuRkEmvXrqVx48b07NmTnj170qRJE3744Yc86wQFBZGQkJCnbcOGDSiKwtChQ/P1aWpqyp49e+jVqxfe3t6MHz+enj17snv37iInLkIIIUrG28WaEe1qATBz6yUysmXwrsjPIK+8lGdy5UUIIUomMT2Lbp8e4G5yBu/29ubNLnX1HZIoIxX6yosQQoiKq6q5Ce8/7QPAwj0hRCWk6TkiUd5I8iKEEKLcGdysBi087EjLymHuH4H6DkeUM5K8CCGEKHdUKhWzBjbESAV/XIjiaMhdfYckyhFJXoQQQpRLDV1teLmNBwAztl4iK0ej54hEeSHJixBCiHJr0lPe2FuZEnw7me+OhOo7HFFOSPIihBCi3LKxNGFK79zBu5/vusqNuyl6jkiUB5K8CCGEKNeeb1GT9nUdSM/S8O4vF9BopMJHZSfJixBCiHJNpVLx0TNNsDRVc+LGPb4/dkPfIQk9k+RFCCFEuedmb8nUPrm3jxZsD+LanWQ9RyT0SZIX8VgjRozI/ebz0Ud52rds2ZJnFvH9+/ejUqkKfEVHRwMwc+ZMbZuxsTGOjo506tSJL7/8koyMjDz9d+nSpcC+Hp6X6kmO5eFXw4YNH7ldWFgY/fv3x8rKCkdHR8aPH09mZuYTxyGEKL5hrT1oV8eBtKwc3vjxNKmZ2foOSeiJJC+iSMzNzVmwYAFxcXGPXTcoKIioqKg8LycnJ+3yhg0bEhUVRVhYGPv27eP5558nICCAdu3akZSUlKevMWPG5Ovr448/fuLj+Oqrr/L0FR4ejr29Pc8//3yh2+Tk5NC3b19SUlI4fPgwGzZs4Ndff2XSpElPHIcQoviMjFR8OcSXatZmXI1J5v1N/yAz3FROkryIIunRowcuLi4EBAQ8dl0nJydcXFzyvIyM/vurZmxsjIuLC66urjRu3Ji33nqLAwcOcPHiRRYsWJCnL0tLy3x9FTbfxbfffkuNGjXQaPLWghgwYADDhw8HwMbGJk9fp06dIi4ujpEjRxZ6PDt37uTy5cv8+OOPNGvWjB49evDZZ5+xfPlyEhMTH/v/QwihO07W5iwa2gy1kYot5yJZsv+avkMSeiDJix4pikJqZrZeXsX9tqJWq5k/fz4LFy4kIiJC5/8vfHx86NOnD5s2bXriPp5//nnu3r3Lvn37tG1xcXHs2LGDYcOGFbjNypUr6dGjBx4eHoX2e+zYMRo1aoSrq6u2rVevXmRkZHD69OknjlcI8WRa13bgg771AfhkRxA//n1TzxGJsmas7wAqs7SsHBp8uEMv+748uxeWpsU7/YMHD8bX15cZM2awcuXKQterWbNmnvc1atQgKCjosf37+Piwc+fOPG1LlixhxYoVedoWL16svZLyIHt7e3r37s26devo3r07AD///DP29vba9w+Kiorir7/+Yt26dY+MKzo6Gmdn5zxtdnZ2mJqaasfyCCHK1sj2ntxNzmDxvmt8sOUiCWlZvNmlTp5xeKLikuRFFMuCBQvo1q3bI8d7HDp0CGtra+17Y+Oi/TVTFCXfL55hw4Yxbdq0PG0Pjp952LBhwxg7dixLlizBzMyMtWvXMmTIENRqdb51V69eja2tLYMGDXpsbAX9QiwoXiFE2Znc05vsHIVvD17nkx1BXIlOYvaAhthZmeo7NFHKJHnRIwsTNZdn99Lbvp9Ep06d6NWrF++//z4jRowocB1PT09sbW2L3XdgYCCenp552mxsbKhbt26R++jfvz8ajYY//viDli1bcujQIT7//PN86ymKwqpVq/D398fU9NG/6FxcXDh+/Hietri4OLKysvJdkRFClB2VSsXUp+vjamvBrG2X2HY+kmPXYnmrW11ebOmG+RP+nhPlnyQveqRSqYp966Y8+Oijj/D19aVevXo66/PKlSts376dqVOnlqgfCwsLnnnmGdauXUtISAj16tXDz88v33oHDhwgJCSEUaNGPbbPtm3bMm/ePKKioqhevTqQO4jXzMyswL6FEGVreLtaNKlpw+Sfz3PtTgoztl7ii91X6dnAmc71nGjuYUt1Gwt9hyl0yPA+OYXeNW7cmGHDhrFw4cICl9++fZv09PQ8bQ4ODpiYmACQnZ1NdHQ0Go2G2NhY9u/fz9y5c/H19eWdd97Js11qamq+cSVmZmbY2dkVGt+wYcPo378/ly5d4uWXXy5wnZUrV9K6dWsaNWqUb9nmzZuZOnUqV65cAaBnz540aNAAf39/PvnkE+7du8fkyZMZM2ZMoU8+CSHKVjN3O/4Y35GfT0fwzf5r3IpP46dTEfx0KvcBg+o25rTytKd9HUe6+FTDydpczxGLkpDkRTyROXPm8NNPPxW4zNvbO1/bsWPHaNOmDQCXLl2ievXqqNVqbGxsaNCgAVOnTuWNN97AzMwsz3bLly9n+fLledp69erF9u3bC42tW7du2NvbExQUxEsvvZRveUJCAr/++itfffVVgdsnJCTkGWCsVqv5448/ePPNN2nfvj0WFha89NJLfPrpp4XGIIQoe+YmavzbePBSK3eOh8ay42I0J2/EcSU6kaiEdH47F8lv5yJRG6noUd+JN7rUxdfNVt9hiyegUqTCj04lJiZiY2NDQkKCfCsXQohyICUjm/Ph8Ry7HsvBq3c4H5GgXda7oQvv9vamdrUqeoxQ3FfUz1BJXnRMkhchhCjfgqKTWHbwOpvPRqBRwNhIxcttPBjf3Qt7eVJJryR50RNJXoQQwjBcjUliwV9X2HPlNgDW5sa81a0uw1p7YGUmoyr0QZIXPZHkRQghDMuRkLvM/SOQwKjc6T6sTNU83bg6nb2r0czdjupVzTEykppOZUGSFz2R5EUIIQxPjkbh1zMRLN1/jdC7KXmWWZio8XCwpKadJe72lrjZW+BmZ4mbvSUeDpZST0aHKnTyMm/ePP744w/OnTuHqakp8fHxj91GURRmzZrFsmXLiIuLo3Xr1ixevJiGDRtq18nIyGDy5MmsX7+etLQ0unfvzpIlS/KVu38USV6EEMJwKYrC39fvsTswhiMhdwm5nUy2pvCPSSMV1HK0or5LVbxdrPF2saaeszUuVc2xMJWkprgqdPIyY8YMbG1tiYiIYOXKlUVKXhYsWMC8efNYvXo19erVY+7cuRw8eJCgoCBtKfs33niDbdu2sXr1ahwcHJg0aRL37t3j9OnTBZaXL4gkL0IIUXFk5WgIv5fKzXupRNxLJTwujfB7qYTHpRIWm0pienah21YxM8axiikOVcyoam6MjYUJVS1MqGpuQlUL43//zPvexsIEa3NjjNWVc97kCp283Ld69WomTJjw2ORFURRcXV2ZMGEC7733HpB7lcXZ2ZkFCxbw2muvkZCQQLVq1fjhhx948cUXAYiMjMTNzY0///yTXr2KVsZfkhchhKgcFEXhTlIGV6KTuBKdmPtnVBLX7yaTnqUpUd+maiNMjf99FfKz2SOWqVUqjIxUqFRgpFLlvlflVnY3UqlQG/33s5EK1Eaqf9/nrm9k9N/PKkClAhUq/v0P1b/tdlYmdPPR3TQpRf0MrRTDqUNDQ4mOjqZnz57aNjMzMzp37szRo0d57bXXOH36NFlZWXnWcXV1pVGjRhw9erTQ5CUjI4OMjAzt+8TExNI7ECGEEOWGSqXCqao5TlXN6VSvmrZdURSSM7K5k5TB3eRMYpMzSErPJjE9i8S0LBLTs0lIu/9zFolp/y1LycwBIDNHQ2aOBjIK23v50KB6VZ0mL0VVKZKX++XlH55Ez9nZmZs3b2rXMTU1zVd23tnZOV95+gcFBAQwa9YsHUcshBDCUKlUKqzNTbA2N6F2tcev/6DsHA2J6dmkZeWQma3575WTQ0ae9/l/znjgvUZRUBTQaBRy7v+sKGgUhRxNboKV+z53He3P99s1//2sKKCQu839WzX32zzsLXX8f69oyk3yMnPmzMcmASdPnqRFixZPvA+VKu+jboqi5Gt72OPWmTp1KhMnTtS+T0xMxM3N7YljFEIIUXkZq42kUF4RlJvkZdy4cQwZMuSR69SqVeuJ+nZxcQFyr67cnxUYcicQvH81xsXFhczMTOLi4vJcfbl9+zbt2rUrtG8zM7N88/EIIYQQovSUm+TF0dERR0fHUunb09MTFxcXdu3aRbNmzQDIzMzkwIEDLFiwAAA/Pz9MTEzYtWsXL7zwAgBRUVFcvHiRjz/+uFTiEkIIIUTxlZvkpTjCwsK4d+8eYWFh5OTkcO7cOQDq1q1LlSq5k2v5+PgQEBDA4MGDUalUTJgwgfnz5+Pl5YWXlxfz58/H0tJSO+uwjY0No0aNYtKkSTg4OGBvb8/kyZNp3LgxPXr00NehCiGEEOIhBpm8fPjhh6xZs0b7/v7VlH379tGlSxcAgoKCSEj4b+bQd999l7S0NN58801tkbqdO3dqa7wAfPHFFxgbG/PCCy9oi9StXr26yDVehBBCCFH6DLrOS3mUkJCAra0t4eHhUudFCCGEKIb7D73Ex8djY2NT6HoGeeWlPEtKSgKQJ46EEEKIJ5SUlPTI5EWuvOiYRqMhMjISa2vrPI9Yt2zZkpMnT+Zbv6D2h9vuZ6L6vJpTWPxl1U9Rt3vceo9aXpxzVFB7ZT9PxdlGX+epIp2jJ+1LV/+WHreO/M4rWV/6/J1X2LKyOE+KopCUlISrqytGRoVPkSBXXnTMyMiowIkc1Wp1gSe3oPbC1q1atare/iEXFlNZ9VPU7R633qOWF+ccPaq9sp6n4myj7/NUEc7Rk/alq39Lj1tHfueVrC99/s4rbFlZnadHXXG5r3LO/KQH//vf/4rcXti6+qSrmJ60n6Ju97j1HrW8OOeoODGVJX2ep+JsU5nPky7jKc3zVJT1dHWeyts5gopznp7kHBW2rDydJ7ltZABkskfDIOep/JNzZBjkPBkGfZ4nufJiAMzMzJgxY4ZU8i3n5DyVf3KODIOcJ8Ogz/MkV16EEEIIYVDkyosQQgghDIokL0IIIYQwKJK8CCGEEMKgSPIihBBCCIMiyUsFlJqaioeHB5MnT9Z3KKIASUlJtGzZEl9fXxo3bszy5cv1HZIoQHh4OF26dKFBgwY0adKEn3/+Wd8hiQIMHjwYOzs7nnvuOX2HIh7w+++/4+3tjZeXFytWrNB5//K0UQU0bdo0goODcXd359NPP9V3OOIhOTk5ZGRkYGlpSWpqKo0aNeLkyZM4ODjoOzTxgKioKGJiYvD19eX27ds0b96coKAgrKys9B2aeMC+fftITk5mzZo1/PLLL/oORwDZ2dk0aNCAffv2UbVqVZo3b87x48ext7fX2T7kyksFExwczJUrV3j66af1HYoohFqtxtLSEoD09HRycnKQ7xDlT/Xq1fH19QXAyckJe3t77t27p9+gRD5du3bF2tpa32GIB5w4cYKGDRtSo0YNrK2tefrpp9mxY4dO9yHJSxk6ePAg/fv3x9XVFZVKxZYtW/Kts2TJEjw9PTE3N8fPz49Dhw4Vax+TJ08mICBARxFXTmVxnuLj42natCk1a9bk3XffxdHRUUfRVx5lcZ7uO3XqFBqNRmaLL6ayPEdCd0p63iIjI6lRo4b2fc2aNbl165ZOY5TkpQylpKTQtGlTFi1aVODyjRs3MmHCBKZNm8bZs2fp2LEjffr0ISwsTLuOn58fjRo1yveKjIzkt99+o169etSrV6+sDqlCKu3zBGBra8v58+cJDQ1l3bp1xMTElMmxVSRlcZ4AYmNjeeWVV1i2bFmpH1NFU1bnSOhWSc9bQVeSVSqVboNUhF4AyubNm/O0tWrVSnn99dfztPn4+ChTpkwpUp9TpkxRatasqXh4eCgODg5K1apVlVmzZukq5EqpNM7Tw15//XXlp59+etIQhVJ65yk9PV3p2LGj8v333+sizEqtNP8t7du3T3n22WdLGqIowJOctyNHjiiDBg3SLhs/fryydu1ancYlV17KiczMTE6fPk3Pnj3ztPfs2ZOjR48WqY+AgADCw8O5ceMGn376KWPGjOHDDz8sjXArLV2cp5iYGBITE4Hcic0OHjyIt7e3zmOtzHRxnhRFYcSIEXTr1g1/f//SCLNS08U5EmWvKOetVatWXLx4kVu3bpGUlMSff/5Jr169dBqHsU57E0/s7t275OTk4OzsnKfd2dmZ6OhoPUUlHqaL8xQREcGoUaNQFAVFURg3bhxNmjQpjXArLV2cpyNHjrBx40aaNGmivef/ww8/0LhxY12HWynp6nder169OHPmDCkpKdSsWZPNmzfTsmVLXYcr/lWU82ZsbMxnn31G165d0Wg0vPvuuzp/mlKSl3Lm4fuCiqI80b3CESNG6CgiUZCSnCc/Pz/OnTtXClGJh5XkPHXo0AGNRlMaYYkHlPR3nq6fYhFF87jzNmDAAAYMGFBq+5fbRuWEo6MjarU63zeO27dv58twhf7IeTIMcp7KPzlHhqm8nDdJXsoJU1NT/Pz82LVrV572Xbt20a5dOz1FJR4m58kwyHkq/+QcGabyct7ktlEZSk5OJiQkRPs+NDSUc+fOYW9vj7u7OxMnTsTf358WLVrQtm1bli1bRlhYGK+//roeo6585DwZBjlP5Z+cI8NkEOdNp88uiUfat2+fAuR7DR8+XLvO4sWLFQ8PD8XU1FRp3ry5cuDAAf0FXEnJeTIMcp7KPzlHhskQzpvMbSSEEEIIgyJjXoQQQghhUCR5EUIIIYRBkeRFCCGEEAZFkhchhBBCGBRJXoQQQghhUCR5EUIIIYRBkeRFCCGEEAZFkhchhBBCGBRJXoQQQghhUCR5EUIIIYRBkeRFCCGEEAZFkhchhBBCGBRJXoQQQghhUP4f9WmRMSk/SF8AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pk_v7 = np.array([k**(3/2)*v7.pk(k*v7.h(), 0.)*v7.h()**3 for k in kk])\n", + "\n", + "fig, ax = plt.subplots(2,1, figsize=[6, 4])\n", + "ax[0].set_xscale('log')\n", + "ax[0].set_yscale('log')\n", + "ax[0].set_ylabel(r'$k^{3/2} P_k$ [Mpc$^3$/h$^3$]')\n", + "ax[0].plot(kk, pk_lcdm, 'k-', label=r'$\\Lambda$CDM')\n", + "ax[0].plot(kk, pk_v7, '-', label=f\"NEDE v7.0\")\n", + "ax[0].legend(frameon=False)\n", + "ax[1].set_ylabel(r'$\\Delta P_k/P_{k,\\Lambda\\mathrm{CDM}}$')\n", + "ax[1].set_xscale('log')\n", + "ax[1].set_yscale('linear')\n", + "ax[1].plot(kk, (pk_v7 - pk_lcdm)/pk_lcdm, '-', label=f\"NEDE v7.0\")\n", + "ax[1].plot(kk, np.zeros(len(kk)), 'k--', lw=0.8)\n", + "ax[1].legend(frameon=False)\n", + "fig.subplots_adjust(hspace=0.)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "c5c2bee9-0ead-427e-a8af-04190ad6b944", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi0AAAFhCAYAAAC8m5r4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAABubElEQVR4nO3deViU5frA8e/MAMMOAgKCCriLG4iaprnlEqm5lqVHzeW06MnUrJNbuWtZZh3T7KepZZlpWVmmqWlaljuUuSuCGyKgbMo28/7+GBgY2ddh8P5c11zOvO/zPu89ozI3z6pSFEVBCCGEEKKKU5s7ACGEEEKI4pCkRQghhBAWQZIWIYQQQlgESVqEEEIIYREkaRFCCCGERZCkRQghhBAWQZIWIYQQQlgESVqEEEIIYREkaRFCCCGERZCkRVisdevWoVKpsLW1JTIyMs/5rl270rx5c5Nj/v7+qFSqfB9du3bNU3f2w9bWFm9vb7p168aiRYuIiYnJc7/Zs2cXWLdKpeLy5cvl/RGU2t27d5k9ezb79u2rkPovX76MSqXinXfeKbc6r1+/zuzZswkLC8tzLvuzt3QLFy7k22+/LVbZiviM75ecnMykSZPw8fHB1taWoKAgvvzyy2Jd+8033/DMM8/QoEED7Ozs8Pf3Z/jw4Zw/f77Aaz744APc3d3JzMxk3759xv8769aty7d89+7dUalU+Pv7l+LdCUtkZe4AhCirtLQ0Zs6cyWeffVas8h07dsz3B72zs3OeY2vXrqVJkyZkZGQQExPDb7/9xltvvcU777zDpk2b6NGjR55rduzYgYuLS57jtWrVKlZ8leHu3bvMmTMHwCRZq8quX7/OnDlz8Pf3JygoyOTcuHHjeOyxx8wTWDlauHAhQ4YMYcCAAeYOBYBBgwZx5MgRFi9eTKNGjfjiiy945pln0Ov1DBs2rNBr33rrLby9vZkxYwb16tXjypUrLFy4kNatW/Pnn3/SrFmzPNd8/fXX9O/fHyurnK8mJycn1qxZw7PPPmtSNiIign379uX7/1ZUX5K0CIv32GOP8cUXXzB16lRatWpVZHlXV1fat29frLqbN29OmzZtjK8HDx7M5MmT6dSpE4MGDeL8+fN4eXmZXBMSEoKHh0fJ3kQlURSF1NRUi62/ILVr16Z27dqVft/qbPv27ezatcuYqAB069aNyMhIXn31VYYOHYpGoynw+m3btuHp6WlyrHv37vj7+/Pee++xevVqk3M3b97kt99+47XXXjM5PnToUFavXs358+dp2LCh8fgnn3yCr68vLVq04NSpU2V9u8JCSPeQsHivvfYa7u7u/Pe//62U+9WtW5d3332XpKQkVq1aVW71+vv707dvX7Zu3UrLli2xtbWlXr16fPDBB3nKJiYmMnXqVAICArCxscHX15dJkyaRkpJiUk6lUvGf//yHjz76iKZNm6LValm/fj01a9YEYM6cOcYm+OzfZJ999tl8m9vz64IpqP5ser2eBQsWULduXWxtbWnTpg179uwxqePChQuMHj2ahg0bYm9vj6+vL/369ePvv/82ltm3bx9t27YFYPTo0caYZ8+eXWBser2et99+myZNmqDVavH09GTkyJFcvXrVpFx2N+KRI0d45JFHsLe3p169eixevBi9Xm9S3/z582ncuDF2dna4urrSsmVL3n///TyfVW6pqam88sorBAUF4eLigpubGx06dOC7777L81mmpKSwfv36fLssiyMjI4NRo0bh6OjIDz/8UKJr77d161YcHR158sknTY6PHj2a69evc+jQoUKvvz9hAfDx8aF27dpcuXKlwPvd33rZs2dP6tSpwyeffGI8ptfrWb9+PaNGjUKtzvs1lv3vctWqVTRq1AitVktgYGC+XVvXrl3jueeeo06dOtjY2ODj48OQIUO4efNmoe9PmIe0tAiL5+TkxMyZM3n55Zf55Zdf6N69e6HlFUUhMzMzz3GNRlPscRGPP/44Go2G/fv35zmn0+ny1K9SqQr9rTRbWFgYkyZNYvbs2Xh7e/P555/z8ssvk56eztSpUwFD106XLl24evUq06dPp2XLlvzzzz+88cYb/P333+zevdvkfXz77bccOHCAN954A29vb9zc3NixYwePPfYYY8eOZdy4cQDGRKak7q8/95fV8uXL8fPzY9myZcYkIjQ0lF9//ZUOHToAhm4fd3d3Fi9eTM2aNYmPj2f9+vU89NBDnDhxgsaNG9O6dWvWrl3L6NGjmTlzJn369AEotHXlxRdf5OOPP+Y///kPffv25fLly8yaNYt9+/Zx/Phxk9aw6Ohohg8fziuvvMKbb77J1q1bmTZtGj4+PowcORKAt99+m9mzZzNz5kw6d+5MRkYGZ86c4c6dO4V+PmlpacTHxzN16lR8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J0+eLJfghDA7XSaEfQHL28D3LxkSFkcvCH0bJp6AtmMlYREPJH9/f1QqFSqVim+//bbAcj169EClUuVZMmPdunXG6wt73L9kRn7XabVaPD09adGiBaNGjWLDhg2kpqYWGNO+ffuKde/SrEtWEgXFEflWX+PDeCwyssT1b9++nR49euDm5oaDgwOtW7fmf//7H3q9vgLeTeUo1UDc559/Hj8/P/bu3cv58+fp378/Go2h//6HH37A3d293AMVolLpdXDyG/h1McRl7TDuUBM6TYY2Y8DazrzxCVGFzJ49m/79+5fqS16r1dKmTcGbg9aqVavI6xRFISEhgcuXL3Py5Ek+/fRTpkyZwsqVKxk8eHCh9+/YsWOJYy4vLi4u+d7/6OXbAGQm3ESXHIevry916tQpUd2LFy9m2rRpANSrVw9HR0fCw8OZOHEiu3fvZuvWragtcFZjiZMWLy8vY1at0+l4+eWXGTt2LI0aNSIlJYXTp08zf/788o5TiMqh18Opb2HfYog9azhm5wYdX4Z2/wYbB7OGJ0RVo9FoCA8P5+uvv2bIkCElvt7b25vffvutXK7T6XQcPnyYxYsX8/333zNkyBA++ugjnn/++QLrKc29y0twcHC+9/d//UcAoje8hi45juHDh5cowfjjjz+YPn06arWaDRs28MwzzwAQHh5O7969+f7771m6dClTp04tnzdSicqUZmk0GpYvX84vv/xC79696datG+vXrzdmd0JYDEWBU9/DRx1hy2hDwmLrCt1nwaS/oNMkSViEyEf2F+KcOXNQFMWssWg0Gjp06MB3333H9OnTAXjppZc4f/68WeMqjYw70aRdOwXAiBEjSnTt/PnzURSFcePGGf9+AFq1asXSpUsBQ0tMRkZG+QVcScqlbSg4OJi5c+fyv//9j3/961/lUaUQlUNR4OxPsKozfDUCYk6B1tmwzsqkvwwDbbVO5o5SiCprzJgx+Pv7c/LkSb766itzh2M0b948goODycjI4N13363Qey1fvhyVSkXfvn0LLBMfH4+NjQ3W1tbExcUVWWfKP3sBCAoKonnz5sWOJTExkd27dwMwduzYPOeffPJJnJ2diYuLY+/evcWut6ooUdISEBBAvXr1Svz44IMPKip+IUpHUeD8bvi/7rDxaYj+C2wcofOrhmSl6+tg62LuKIWo8qytrZkxYwZgaG2p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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pt_v7 = v7.get_perturbations()['scalar'][0]\n", + "fig, ax = plt.subplots(2,1, figsize=[6, 4])\n", + "ax[0].set_title(f'NEDE perturbations at k={k_plot}/Mpc')\n", + "ax[0].set(xscale='log', yscale='log', xticks=[], ylabel=r'$|\\delta|$')\n", + "ax[0].plot(pt_v7['a'], np.abs(pt_v7['delta_NEDE']), '-', label=f\"NEDE v7.0\")\n", + "ax[1].plot(pt_v7['a'], np.abs(pt_v7['theta_NEDE']), '-', label=f\"NEDE v7.0\")\n", + "ax[0].plot(pt_v7['a'], np.abs(pt_v7['delta_trigger']), '-', label=f\"trigger v7.0\")\n", + "ax[0].legend(frameon=False, fontsize=16)\n", + "ax[1].set(xscale='log', yscale='log', xticks=[], ylabel=r'$|\\theta|$')\n", + "ax[1].legend(frameon=False, fontsize=16)\n", + "fig.subplots_adjust(hspace=0.)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/cclassy.pxd b/python/cclassy.pxd index 19d8a6e0a..7fdc30561 100644 --- a/python/cclassy.pxd +++ b/python/cclassy.pxd @@ -104,6 +104,10 @@ cdef extern from "class.h": double H_eq double z_eq double tau_eq + short has_NEDE + double a_trigger_fluid + double NEDE_trigger_ini + double NEDE_trigger_mass cdef struct thermodynamics: ErrorMsg error_message diff --git a/python/classy.pyx b/python/classy.pyx index b2ea1fccf..bd4ee6130 100644 --- a/python/classy.pyx +++ b/python/classy.pyx @@ -2455,6 +2455,21 @@ cdef class Class: value = self.ba.H_eq elif name == 'tau_eq': value = self.ba.tau_eq + elif name == 'a_trigger_fluid': + if (self.ba.has_NEDE == _TRUE_): + value = self.ba.a_trigger_fluid + else: + raise CosmoSevereError("You have asked for 'a_trigger_fluid', but did not run with NEDE.") + elif name == 'NEDE_trigger_ini': + if (self.ba.has_NEDE == _TRUE_): + value = self.ba.NEDE_trigger_ini + else: + raise CosmoSevereError("You have asked for 'NEDE_trigger_ini', but did not run with NEDE.") + elif name == 'NEDE_trigger_mass': + if (self.ba.has_NEDE == _TRUE_): + value = self.ba.NEDE_trigger_mass + else: + raise CosmoSevereError("You have asked for 'NEDE_trigger_mass', but did not run with NEDE.") elif name == 'g_sd': self.compute(["distortions"]) if (self.sd.has_distortions == _FALSE_): diff --git a/source/background.c b/source/background.c index 22246e23e..2b47c592c 100644 --- a/source/background.c +++ b/source/background.c @@ -404,7 +404,11 @@ int background_functions( p_prime = a_prime_over_a * dp_dloga = a_prime_over_a * Sum [ (w_prime/a_prime_over_a -3(1+w)w)rho]. Note: The scalar field contribution must be added in the end, as an exception!*/ double dp_dloga; - + + /* NEDE */ + double rho_NEDE_decay; + double w_NEDE, dw_over_da_NEDE; + /** - initialize local variables */ rho_tot = 0.; p_tot = 0.; @@ -489,6 +493,72 @@ int background_functions( //printf(" a= %e, Omega_scf = %f, \n ",a, pvecback[pba->index_bg_rho_scf]/rho_tot ); } + /* NEDE */ + if (pba->has_NEDE == _TRUE_) { + double a_decay = 1./(1. + pba->z_decay_NEDE); + if (a < a_decay || a_decay == 0) { + /* w=-1 phase */ + /* Note the class convention according to which 3 Mpl^2 is absorbed in rho, i.e. rho_crit = H0^2. */ + rho_NEDE_decay = pba->Omega_NEDE * pow(pba->H0, 2); + /* Save value of rho in array for later use. */ + pvecback[pba->index_bg_rho_NEDE] = rho_NEDE_decay; + pvecback[pba->index_bg_w_NEDE] = -1; + + p_tot -= rho_NEDE_decay; /* add pressure contributio n*/ + rho_tot += rho_NEDE_decay; /* add energy contribution */ + } + else { + /* NEDE decay phase with w > 0 */ + class_call(background_quantities_NEDE(pba, a, 0, &rho_NEDE_decay, NULL, &w_NEDE, &dw_over_da_NEDE, NULL), + pba->error_message, + pba->error_message); + + pvecback[pba->index_bg_rho_NEDE] = rho_NEDE_decay; + pvecback[pba->index_bg_w_NEDE] = w_NEDE; + p_tot += w_NEDE * rho_NEDE_decay; + rho_tot += rho_NEDE_decay; + + dp_dloga += (a*dw_over_da_NEDE - 3*(1 + w_NEDE)*w_NEDE)*pvecback[pba->index_bg_rho_NEDE]; + } + } + + /* NEDE trigger field */ + if (pba->has_NEDE_trigger == _TRUE_) { + if (pba->trigger_fluid_approximation == _FALSE_) { + // This part is relevant before the fluid approximation is turned on. + phi = pvecback_B[pba->index_bi_phi_trigger]; + phi_prime = pvecback_B[pba->index_bi_phi_prime_trigger]; + pvecback[pba->index_bg_V_trigger] = V_trigger(pba, phi); // V_scf(pba,phi); //write here potential as function of phi + pvecback[pba->index_bg_dV_trigger] = dV_trigger(pba, phi); // dV_scf(pba,phi); //potential' as function of phi + pvecback[pba->index_bg_ddV_trigger] = ddV_trigger(pba, phi); // ddV_scf(pba,phi); //potential'' as function of phi + pvecback[pba->index_bg_phi_trigger] = phi; // value of the trigger field phi + pvecback[pba->index_bg_phi_prime_trigger] = phi_prime; // value of the trigger field derivative wrt conformal time + pvecback[pba->index_bg_rho_trigger] = (phi_prime*phi_prime/(2*a*a) + V_trigger(pba, phi))/3.; // energy of the trigger field. The field units are set automatically by setting the initial conditions + pvecback[pba->index_bg_p_trigger] = (phi_prime*phi_prime/(2*a*a) - V_trigger(pba, phi))/3.; // pressure of the trigger field + + rho_tot += pvecback[pba->index_bg_rho_trigger]; + p_tot += pvecback[pba->index_bg_p_trigger]; + dp_dloga += 0.0; /** <-- This depends on a_prime_over_a, so we cannot add it now! */ + + // divide relativistic & nonrelativistic (not very meaningful for oscillatory models) + rho_r += 3.*pvecback[pba->index_bg_p_trigger]; // field pressure contributes radiation + rho_m += pvecback[pba->index_bg_rho_trigger] - 3.*pvecback[pba->index_bg_p_trigger]; // the rest contributes matter + } + else { + // This part is relevant after the fluid approximation has been turned on. + // Here we copy the fluid energy density from the integration vector and add it to rho_tot. + pvecback[pba->index_bg_rho_trigger] = pvecback_B[pba->index_bi_rho_trigger]; + // Everything is set below! + + // And add it to the total energy density. + rho_tot += pvecback[pba->index_bg_rho_trigger]; + + // Everything else is added later after we have calculated H and H_prime below. + dp_dloga += 0.0; + p_tot += 0.0; + } + } + /* ncdm */ if (pba->has_ncdm == _TRUE_) { @@ -563,7 +633,7 @@ int background_functions( dp_dloga += -(4./3.) * pvecback[pba->index_bg_rho_ur]; rho_r += pvecback[pba->index_bg_rho_ur]; } - + /* interacting dark radiation */ if (pba->has_idr == _TRUE_) { pvecback[pba->index_bg_rho_idr] = pba->Omega0_idr * pow(pba->H0,2) / pow(a,4); @@ -571,6 +641,34 @@ int background_functions( p_tot += (1./3.) * pvecback[pba->index_bg_rho_idr]; rho_r += pvecback[pba->index_bg_rho_idr]; } + + if (pba->has_NEDE_trigger == _TRUE_) { + // NEDE: Here we calculate the pressure contribution of the Trigger field when we are in the fluid approximation. + if (pba->trigger_fluid_approximation == _TRUE_) { + double w_trigger; + class_call(background_quantities_NEDE_trigger(pba, a, a*pvecback[pba->index_bg_H], pvecback[pba->index_bg_H], 0, &w_trigger, NULL, NULL), + pba->error_message, + pba->error_message); + + pvecback[pba->index_bg_p_trigger] = w_trigger * pvecback[pba->index_bg_rho_trigger]; // pressure of the trigger field + p_tot += pvecback[pba->index_bg_p_trigger]; + + dp_dloga += 0.0; // Add later after we have H_prime //(a * dw_over_da_trigger - 3 * (1 + w_trigger) * w_fld) * pvecback[pba->index_bg_rho_fld]; + + // divide relativistic & nonrelativistic (not very meaningful for oscillatory models) + rho_r += 3. * pvecback[pba->index_bg_p_trigger]; // field pressure contributes radiation + rho_m += pvecback[pba->index_bg_rho_trigger] - 3. * pvecback[pba->index_bg_p_trigger]; // the rest contributes matter + + // Everything else is not tracked; just set to zero. + pvecback[pba->index_bg_V_trigger] = V_trigger(pba, 0.); + pvecback[pba->index_bg_dV_trigger] = dV_trigger(pba, 0.); + pvecback[pba->index_bg_ddV_trigger] = ddV_trigger(pba, 0.); + // pvecback[pba->index_bg_phi_trigger] = sqrt(pvecback[pba->index_bg_rho_trigger] - pvecback[pba->index_bg_p_trigger])/pba->NEDE_trigger_mass; + // pvecback[pba->index_bg_phi_prime_trigger] = sqrt(pvecback[pba->index_bg_rho_trigger] + pvecback[pba->index_bg_p_trigger]); + pvecback[pba->index_bg_phi_trigger] = 0.; + pvecback[pba->index_bg_phi_prime_trigger] = 0.; + } + } /** - compute expansion rate H from Friedmann equation: this is the only place where the Friedmann equation is assumed. Remember @@ -595,6 +693,30 @@ int background_functions( (-pvecback[pba->index_bg_phi_prime_scf]*pvecback[pba->index_bg_H]/a-2./3.*pvecback[pba->index_bg_dV_scf]); pvecback[pba->index_bg_p_tot_prime] += pvecback[pba->index_bg_p_prime_scf]; } + + if (pba->has_NEDE_trigger == _TRUE_) { + /** The contribution of the trigger field was not added to dp_dloga, add p_scf_prime here: */ + pvecback[pba->index_bg_w_trigger] = 0.; + pvecback[pba->index_bg_ca2_trigger] = 0.; + if (pba->trigger_fluid_approximation == _FALSE_) { + pvecback[pba->index_bg_p_prime_trigger] = pvecback[pba->index_bg_phi_prime_trigger]*(-pvecback[pba->index_bg_phi_prime_trigger]*pvecback[pba->index_bg_H]/a - 2./3.*pvecback[pba->index_bg_dV_trigger]); + pvecback[pba->index_bg_p_tot_prime] += pvecback[pba->index_bg_p_prime_trigger]; + } + else { + // Similarly in the fluid case. + double w_trigger, dw_over_da_trigger, ca2_trigger; + class_call(background_quantities_NEDE_trigger(pba, a, a*pvecback[pba->index_bg_H], pvecback[pba->index_bg_H], pvecback[pba->index_bg_H_prime], &w_trigger, &dw_over_da_trigger, &ca2_trigger), + pba->error_message, + pba->error_message); + + pvecback[pba->index_bg_w_trigger] = w_trigger; + pvecback[pba->index_bg_ca2_trigger] = ca2_trigger; + + double dp_dloga_trigger = (a*dw_over_da_trigger - 3.*(1. + w_trigger)*w_trigger)*pvecback[pba->index_bg_rho_trigger]; + pvecback[pba->index_bg_p_prime_trigger] = 0.; // Not tracked in fluid approximation + pvecback[pba->index_bg_p_tot_prime] += a*pvecback[pba->index_bg_H]*dp_dloga_trigger; + } + } /** - compute critical density */ rho_crit = rho_tot-pba->K/a/a; @@ -610,7 +732,16 @@ int background_functions( /** - store critical density */ pvecback[pba->index_bg_rho_crit] = rho_crit; - + + if (pba->has_NEDE_trigger == _TRUE_) { + if (pba->trigger_fluid_approximation == _TRUE_) { + pvecback[pba->index_bg_rho_trigger] = pvecback_B[pba->index_bi_rho_trigger]; + if (pvecback[pba->index_bg_rho_trigger] < 0.) { + printf("rho_trigger=%g negative at a=%g in background functions; rho_crit=%g, Omega0_trigger=%g\n", pvecback[pba->index_bg_rho_trigger], a, pvecback[pba->index_bg_rho_crit], pvecback[pba->index_bg_rho_trigger]/pvecback[pba->index_bg_rho_crit]); + } + } + } + /** - compute Omega_m */ pvecback[pba->index_bg_Omega_m] = rho_m / rho_crit; @@ -750,6 +881,89 @@ int background_w_fld( return _SUCCESS_; } +/** + * Single place where the NEDE fluid equation of state is + * defined. Parameters of the function are passed through the + * background structure. Generalisation to arbitrary functions should + * be simple. + * + * @param pba Input: pointer to background structure + * @param a Input: current value of scale factor + * @param a_prime_over_a Input: Hubble parameter + * @param rho Output: rho_NEDE(a) + * @param p Output: p_NEDE(a) + * @param w Output: equation of state parameter w_NEDE(a) + * @param dw_over_da Output: function dw_NEDE/da + * @param ca2 Output: adiabatic sound speed$ + * @return the error status + */ + +int background_quantities_NEDE( + struct background *pba, + double a, + double a_prime_over_a, + double *rho, + double *p, + double *w, + double *dw_over_da, + double *ca2) +{ + double w_prime; + double w_local = 0.; + double rho_local; + + switch (pba->NEDE_fld_nature) + { + case NEDE_fld_A: + w_local = pba->three_eos_NEDE / 3.; + rho_local = (pba->Omega_NEDE) * pow(pba->H0, 2) * pow(1./(1. + pba->z_decay_NEDE) / a, 3. + 3. * w_local); + w_prime = 0.; + + if (w != NULL) + *w = w_local; + if (dw_over_da != NULL) + *dw_over_da = 0; + if (rho != NULL) + *rho = rho_local; + if (p != NULL) + *p = w_local * rho_local; + if ((ca2 != NULL) && (a_prime_over_a != 0.)) + *ca2 = w_local - w_prime / 3. / (1. + w_local) / a_prime_over_a; + + break; + } + + return _SUCCESS_; +} + +int background_quantities_NEDE_trigger( + struct background *pba, + double a, + double a_prime_over_a, + double H, + double H_prime, + double *w, + double *dw_over_da, + double *ca2) +{ + double w_prime; + double w_local = 0.; + + // We use the description proposed in arXiv:2201.10238 + + w_local = 3.0 / 2.0 * pow(H / pba->NEDE_trigger_mass, 2); + w_prime = w_local * 2 * H_prime / H; + + if (w != NULL) + *w = w_local; + if (dw_over_da != NULL) + *dw_over_da = w_prime / a / a / H; + if ((ca2 != NULL) && (a_prime_over_a != 0.)) + *ca2 = w_local - w_prime / 3. / (1. + w_local) / a_prime_over_a; + + return _SUCCESS_; +} + /** * Single place where the variation of fundamental constants is * defined. Parameters of the function are passed through the @@ -821,16 +1035,6 @@ int background_init( "Shooting failed, try optimising input_get_guess(). Error message:\n\n%s", pba->shooting_error); - /** - assign values to all indices in vectors of background quantities */ - class_call(background_indices(pba), - pba->error_message, - pba->error_message); - - /** - check that input parameters make sense and write additional information about them */ - class_call(background_checks(ppr,pba), - pba->error_message, - pba->error_message); - /** - integrate the background over log(a), allocate and fill the background table */ class_call(background_solve(ppr,pba), pba->error_message, @@ -983,6 +1187,9 @@ int background_indices( pba->has_idr = _FALSE_; pba->has_curvature = _FALSE_; pba->has_varconst = _FALSE_; + pba->has_NEDE = _FALSE_; + pba->has_NEDE_pert = _FALSE_; + pba->has_NEDE_trigger = _FALSE_; if (pba->Omega0_cdm != 0.) pba->has_cdm = _TRUE_; @@ -998,6 +1205,13 @@ int background_indices( if (pba->Gamma_dcdm != 0.) pba->has_dr = _TRUE_; } + + if (pba->f_NEDE != 0.) { + pba->has_NEDE = _TRUE_; + pba->has_NEDE_trigger = _TRUE_; + pba->has_NEDE_pert = _TRUE_; + pba->has_NEDE_trigger_DM = _TRUE_; + } if (pba->Omega0_scf != 0.) pba->has_scf = _TRUE_; @@ -1099,6 +1313,21 @@ int background_indices( /* */ /* */ + /* - NEDE indices */ + class_define_index(pba->index_bg_rho_NEDE, pba->has_NEDE, index_bg, 1); + class_define_index(pba->index_bg_w_NEDE, pba->has_NEDE, index_bg, 1); + /* - NEDE trigger indices */ + class_define_index(pba->index_bg_phi_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_phi_prime_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_V_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_dV_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_ddV_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_rho_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_p_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_p_prime_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_w_trigger, pba->has_NEDE_trigger, index_bg, 1); + class_define_index(pba->index_bg_ca2_trigger, pba->has_NEDE_trigger, index_bg, 1); + /* - end of indices in the normal vector of background values */ pba->bg_size_normal = index_bg; @@ -1164,6 +1393,23 @@ int background_indices( /* -> scalar field and its derivative wrt conformal time (Zuma) */ class_define_index(pba->index_bi_phi_scf,pba->has_scf,index_bi,1); class_define_index(pba->index_bi_phi_prime_scf,pba->has_scf,index_bi,1); + + /* -> NEDE trigger field, its derivative and energy density + Important that these are the last defined B bi indices! */ + if (pba->has_NEDE_trigger == _TRUE_) { + if (pba->trigger_fluid_approximation == _TRUE_) { + // Only rho is evolved within the fluid approximation + class_define_index(pba->index_bi_rho_trigger, _TRUE_, index_bi, 1); + pba->index_bi_phi_trigger = -1; + pba->index_bi_phi_prime_trigger = -1; + } + else { + // Not fluid approximation, evolve the field itself + class_define_index(pba->index_bi_phi_trigger, _TRUE_, index_bi, 1); + class_define_index(pba->index_bi_phi_prime_trigger, _TRUE_, index_bi, 1); + pba->index_bi_rho_trigger = -1; + } + } /* End of {B} variables */ pba->bi_B_size = index_bi; @@ -1794,6 +2040,14 @@ int background_checks( pba->error_message, "incorrect transition redshift"); } + + if (pba->has_NEDE == _TRUE_) { + class_test(pba->f_NEDE > 0.4, pba->error_message, + "Choose a smaller amount of NEDE as the code has not been tested for f_NEDE > 0.4."); + + class_test(pba->NEDE_trigger_ini < 0., pba->error_message, + "NEDE trigger field cannot run with negative initial value."); + } /** - in verbose mode, send to standard output some additional information on non-obvious background parameters */ if (pba->background_verbose > 0) { @@ -1901,6 +2155,16 @@ int background_solve( /* index of ncdm species */ int n_ncdm; + + /** - assign values to all indices in vectors of background quantities */ + class_call(background_indices(pba), + pba->error_message, + pba->error_message); + + /** - check that input parameters make sense and write additional information about them */ + class_call(background_checks(ppr,pba), + pba->error_message, + pba->error_message); /** - setup background workspace */ bpaw.pba = pba; @@ -1954,6 +2218,13 @@ int background_solve( printf("%s\n", "Chose ndf15 as generic_evolver"); } break; + + case rkdp45: + generic_evolver = evolver_rkdp45; + if (pba->background_verbose > 1) { + printf("%s\n", "Chose rkdp45 as generic_evolver"); + } + break; } /** - perform the integration */ @@ -1975,7 +2246,77 @@ int background_solve( pba->error_message), pba->error_message, pba->error_message); - + + double* new_pvecback_integration; + if (pba->has_NEDE_trigger == _TRUE_) { + if (pba->a_trigger_fluid != 100.) { + // Fluid approximation was requested; integration was stopped early, continue integration with new variables + + /** - Get background quantities at end of last integration; required for computing initial rho_trigger when approx is turned on + (important to do this before changing indices in the next step) */ + double* pvecback; + class_alloc(pvecback,pba->bg_size*sizeof(double),pba->error_message); + double a = pba->a_trigger_fluid_safe; + //printf("\n\nAT FLUID APPROXIMATION TRIGGER: a_trigger_fluid_safe=%g\n", a); + class_call(background_functions(pba, a, pvecback_integration, normal_info, pvecback), + pba->error_message, + pba->error_message); + + /** - Here we implement the matching between the fluid and field description proposed in arXiv:2201.10238. We use Eq.8, Eq. 6 and Eq. 13 */ + double phi_fluid = pvecback_integration[pba->index_bi_phi_trigger]; + double phi_prime_fluid = pvecback_integration[pba->index_bi_phi_prime_trigger]; + double factor = 6.*pow(pvecback[pba->index_bg_H], 2)/(9.*pow(pvecback[pba->index_bg_H], 4) - 4.*(4.*pow(pvecback[pba->index_bg_H], 2)* pow(pba->NEDE_trigger_mass, 2) + pow(pvecback[pba->index_bg_H_prime], 2) / pow(a, 2))); + double phi_c_p = factor*(4.*pvecback[pba->index_bg_H]*pba->NEDE_trigger_mass*phi_fluid + 3.*pow(pvecback[pba->index_bg_H], 2)*phi_prime_fluid/a/pba->NEDE_trigger_mass + 2.*pvecback[pba->index_bg_H_prime]*phi_prime_fluid/pow(a, 2)/pba->NEDE_trigger_mass); + double phi_s_p = factor*(3.*pow(pvecback[pba->index_bg_H], 2)*phi_fluid - 2.*pvecback[pba->index_bg_H_prime]/a*phi_fluid + 4.*pvecback[pba->index_bg_H]*phi_prime_fluid/a); + double phi_c = phi_fluid; + double phi_s = phi_prime_fluid/a/pba->NEDE_trigger_mass - phi_c_p; + double rho_tfa = 0.5*pow(pba->NEDE_trigger_mass, 2)*(phi_c*phi_c + phi_s*phi_s + 0.5*(phi_c_p*phi_c_p + phi_s_p*phi_s_p) - phi_c*phi_s_p + phi_s*phi_c_p); + rho_tfa /= 3.; // CLASS convention! + + pba->trigger_fluid_approximation = _TRUE_; + if (pba->background_verbose > 1) { + printf("Turned on NEDE trigger fluid approximation at a=%g with rho_trigger=%g, matching the FA initial value rho_trigger=%g.\n", pvecback[pba->index_bg_a], pvecback[pba->index_bg_rho_trigger], rho_tfa); + } + + /** - assign new indices after approximation turned on */ + class_call(background_indices(pba), + pba->error_message, + pba->error_message); + + /** - copy variables from last integration vector to the new one */ + class_alloc(new_pvecback_integration,pba->bi_size*sizeof(double),pba->error_message); + for (int index_bi_new = 0; index_bi_new < pba->index_bi_rho_trigger; index_bi_new++) { + // Copy bi A and bi B variables into new set of variables + new_pvecback_integration[index_bi_new] = pvecback_integration[index_bi_new]; + } + new_pvecback_integration[pba->index_bi_rho_trigger] = rho_tfa; + for (int index_bi_new = pba->index_bi_rho_trigger + 1; index_bi_new < pba->bi_size; index_bi_new++) { + // Copy bi C variables + new_pvecback_integration[index_bi_new] = pvecback_integration[index_bi_new + 1]; // +1 because new_pvecback has 1 less bi B variable defined + } + class_call(generic_evolver(background_derivs, + log(pba->a_trigger_fluid_safe), + loga_final, + new_pvecback_integration, + used_in_output, + pba->bi_size, + &bpaw, + ppr->tol_background_integration, + ppr->smallest_allowed_variation, + background_timescale, //'evaluate_timescale', required by evolver_rk but not by ndf15 + ppr->background_integration_stepsize, + pba->loga_table, + pba->bt_size, + background_sources, + NULL, //'print_variables' in evolver_rk could be set, but, not required + pba->error_message), + pba->error_message, + pba->error_message); + free(pvecback_integration); + pvecback_integration = new_pvecback_integration; + } + } + /** - recover some quantities today */ /* -> age in Gyears */ pba->age = pvecback_integration[pba->index_bi_time]/_Gyr_over_Mpc_; @@ -2069,6 +2410,21 @@ int background_solve( pba->Omega0_dr+pba->Omega0_dcdm,pba->Omega0_dcdmdr); printf(" -> Omega_ini_dcdm/Omega_b = %f\n",pba->Omega_ini_dcdm/pba->Omega0_b); } + if (pba->has_NEDE == _TRUE_) + { + printf(" -> NEDE details:\n"); + printf(" -> NEDE decay time: %.2f \n", pba->z_decay_NEDE); + printf(" -> NEDE fraction: %.4f \n", pba->f_NEDE); + if (pba->NEDE_fld_nature == NEDE_fld_A) + printf(" -> Scenario A with eos NEDE: 3*w = %.2f \n", pba->three_eos_NEDE); + printf(" -> Percolation trigger (H/m): %f \n", pba->Bubble_trigger_H_over_m); + printf(" -> closure check: H/H0-1: %e \n", pvecback[pba->index_bg_H] / pba->H0 - 1); + if (pba->has_NEDE_trigger == _TRUE_) { + double rho_crit = pba->background_table[(pba->bt_size-1)*pba->bg_size+pba->index_bg_rho_crit]; + printf(" -> Omega0_trigger = %g, Trigger_ini = %g \n", + pba->background_table[(pba->bt_size-1)*pba->bg_size+pba->index_bg_rho_trigger] / rho_crit, pba->NEDE_trigger_ini); + } + } if (pba->has_scf == _TRUE_) { printf(" Scalar field details:\n"); printf(" -> Omega_scf = %g, wished %g\n", @@ -2090,6 +2446,12 @@ int background_solve( pba->Omega0_m = pba->background_table[(pba->bt_size-1)*pba->bg_size+pba->index_bg_Omega_m]; pba->Omega0_r = pba->background_table[(pba->bt_size-1)*pba->bg_size+pba->index_bg_Omega_r]; pba->Omega0_de = 1. - (pba->Omega0_m + pba->Omega0_r + pba->Omega0_k); + + if (pba->has_NEDE) { + double rho_crit = pba->background_table[(pba->bt_size-1)*pba->bg_size+pba->index_bg_rho_crit]; + pba->Omega0_NEDE = pba->background_table[(pba->bt_size-1)*pba->bg_size+pba->index_bg_rho_NEDE]/rho_crit; + pba->Omega0_trigger = pba->background_table[(pba->bt_size-1)*pba->bg_size+pba->index_bg_rho_trigger]/rho_crit; + } /* Compute the density fraction of non-free-streaming matter (in the minimal LambdaCDM model, this would be just Omega_b + Omega_cdm). This definition takes into account interating, decaying and warm dark matter, but it would need to be refined if some part of the matter component was modelled by the fluid (fld) or the scalar field (scf). */ pba->Omega0_nfsm = pba->Omega0_b; @@ -2252,6 +2614,16 @@ int background_initial_conditions( pvecback_integration[pba->index_bi_rho_fld] = rho_fld_today * exp(integral_fld); } + + + /* NEDE: Here we specify the initial conditions for the trigger field in slow roll approximation. + We simply set it on the attractor. We could also have started with zero, as the attractor is approached quickly + */ + if (pba->has_NEDE_trigger == _TRUE_ && pba->has_NEDE == _TRUE_) { + /* phi'_ini = -1/5 * phi_ini a^2 m^2 / (a H) where H = sqrt(rho) ins class conventions. */ + pvecback_integration[pba->index_bi_phi_trigger] = pba->NEDE_trigger_ini; + pvecback_integration[pba->index_bi_phi_prime_trigger] = -1./5.*pba->NEDE_trigger_ini*pow(pba->NEDE_trigger_mass, 2)/pow(rho_rad, 0.5)*a; + } /** - Fix initial value of \f$ \phi, \phi' \f$ * set directly in the radiation attractor => fixes the units in terms of rho_ur @@ -2374,6 +2746,18 @@ int background_find_equality( class_alloc(pvecback,pba->bg_size*sizeof(double),pba->error_message); + // Always do at least one iteration + tau_mid = 0.5*(tau_plus+tau_minus); + class_call(background_at_tau(pba,tau_mid,long_info,inter_closeby,&index_tau_minus,pvecback), + pba->error_message, + pba->error_message); + Omega_m_over_Omega_r = pvecback[pba->index_bg_Omega_m]/pvecback[pba->index_bg_Omega_r]; + if (Omega_m_over_Omega_r > 1) + tau_plus = tau_mid; + else + tau_minus = tau_mid; + + // Then iterate until desired precision is reached while ((tau_plus - tau_minus) > ppr->tol_tau_eq) { tau_mid = 0.5*(tau_plus+tau_minus); @@ -2454,6 +2838,20 @@ int background_output_titles( class_store_columntitle(titles,"(.)rho_crit",_TRUE_); class_store_columntitle(titles,"(.)rho_dcdm",pba->has_dcdm); class_store_columntitle(titles,"(.)rho_dr",pba->has_dr); + + /* NEDE titles */ + class_store_columntitle(titles, "(.)rho_NEDE", pba->has_NEDE); + class_store_columntitle(titles, "(.)w_NEDE", pba->has_NEDE); + class_store_columntitle(titles, "(.)rho_trigger", pba->has_NEDE_trigger); + class_store_columntitle(titles, "(.)p_trigger", pba->has_NEDE_trigger); + class_store_columntitle(titles, "(.)p_prime_trigger", pba->has_NEDE_trigger); + class_store_columntitle(titles, "phi_trigger", pba->has_NEDE_trigger); + class_store_columntitle(titles, "phi'_trigger", pba->has_NEDE_trigger); + class_store_columntitle(titles, "V_trigger", pba->has_NEDE_trigger) + class_store_columntitle(titles, "dV_trigger", pba->has_NEDE_trigger) + class_store_columntitle(titles, "ddV_trigger", pba->has_NEDE_trigger) + class_store_columntitle(titles, "w_trigger", pba->has_NEDE_trigger) + class_store_columntitle(titles, "ca2_trigger", pba->has_NEDE_trigger) class_store_columntitle(titles,"(.)rho_scf",pba->has_scf); class_store_columntitle(titles,"(.)p_scf",pba->has_scf); @@ -2528,6 +2926,19 @@ int background_output_data( class_store_double(dataptr,pvecback[pba->index_bg_rho_dcdm],pba->has_dcdm,storeidx); class_store_double(dataptr,pvecback[pba->index_bg_rho_dr],pba->has_dr,storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_rho_NEDE], pba->has_NEDE, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_w_NEDE], pba->has_NEDE, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_rho_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_p_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_p_prime_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_phi_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_phi_prime_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_V_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_dV_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_ddV_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_w_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, pvecback[pba->index_bg_ca2_trigger], pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr,pvecback[pba->index_bg_rho_scf],pba->has_scf,storeidx); class_store_double(dataptr,pvecback[pba->index_bg_p_scf],pba->has_scf,storeidx); class_store_double(dataptr,pvecback[pba->index_bg_p_prime_scf],pba->has_scf,storeidx); @@ -2657,6 +3068,21 @@ int background_derivs( dy[pba->index_bi_phi_scf] = y[pba->index_bi_phi_prime_scf]/a/H; dy[pba->index_bi_phi_prime_scf] = - 2*y[pba->index_bi_phi_prime_scf] - a*dV_scf(pba,y[pba->index_bi_phi_scf])/H ; } + + if (pba->has_NEDE_trigger == _TRUE_) { + if ((a >= pba->a_trigger_fluid) && (pba->trigger_fluid_approximation == _TRUE_)) { + // Fluid approximation; track only rho_trigger + double w_trigger, dw_over_da_trigger; + class_call(background_quantities_NEDE_trigger(pba, a, a*H, H, pvecback[pba->index_bg_H_prime], &w_trigger, &dw_over_da_trigger, NULL), pba->error_message, pba->error_message); + dy[pba->index_bi_rho_trigger] = -3.*(1. + w_trigger)*y[pba->index_bi_rho_trigger]; + } + else { + /** - Scalar field equation: \f$ \phi'' + 2 a H \phi' + a^2 dV = 0 \f$ (note H is wrt cosmic time) */ + /** Here transformed to derivatives wrt. loga through d/dloga = 1/(aH)*d/deta, with eta conformal time */ + dy[pba->index_bi_phi_trigger] = y[pba->index_bi_phi_prime_trigger]/a/H; + dy[pba->index_bi_phi_prime_trigger] = -2*y[pba->index_bi_phi_prime_trigger] - a*dV_trigger(pba, y[pba->index_bi_phi_trigger])/H; + } + } return _SUCCESS_; @@ -2719,7 +3145,27 @@ int background_sources( class_call(background_functions(pba, a, y, long_info, bg_table_row), pba->error_message, pba->error_message); - + + if (pba->has_NEDE_trigger == _TRUE_) { + double H = bg_table_row[pba->index_bg_H]; + if (H < pba->trigger_fluid_H_over_m*pba->NEDE_trigger_mass && a > 1./(pba->z_decay_NEDE + 1)) { + if (pba->a_trigger_fluid == 100.) { + // Turn on NEDE trigger fluid approximation (only if NEDE has already decayed) + //printf("From BG Sources: Turned on FA at a=%g\n", a); + //printf("At this time, pba->trigger_fluid_approximation=%d\n", pba->trigger_fluid_approximation); + pba->a_trigger_fluid = a; + pba->H_fluid = H; + pba->H_prime_fluid = bg_table_row[pba->index_bg_H_prime]; + } + else if (pba->trigger_fluid_approximation == _FALSE_) { + if (H*pba->trigger_fluid_safety_factor < pba->trigger_fluid_H_over_m*pba->NEDE_trigger_mass) { // 1.05 is a safety factor, same as in old TriggerCLASS + //printf("From BG Sources: Set a_trigger_fluid_safe at a=%g\n", a); + pba->a_trigger_fluid_safe = a; + return _APPROXIMATION_REACHED_; + } + } + } + } return _SUCCESS_; } @@ -2835,7 +3281,7 @@ int background_output_budget( budget_radiation+=pba->Omega0_idr; } - if ((pba->has_lambda == _TRUE_) || (pba->has_fld == _TRUE_) || (pba->has_scf == _TRUE_) || (pba->has_curvature == _TRUE_)) { + if ((pba->has_lambda == _TRUE_) || (pba->has_fld == _TRUE_) || (pba->has_scf == _TRUE_) || (pba->has_curvature == _TRUE_) || (pba->has_NEDE)) { printf(" ---> Other Content \n"); } if (pba->has_lambda == _TRUE_) { @@ -2854,7 +3300,15 @@ int background_output_budget( class_print_species("Spatial Curvature",k); budget_other+=pba->Omega0_k; } - + if (pba->has_NEDE == _TRUE_) { + class_print_species("New EDE", NEDE); + budget_other += pba->Omega0_NEDE; + } + if (pba->has_NEDE_trigger == _TRUE_) { + class_print_species("New EDE trigger", trigger); + budget_other += pba->Omega0_trigger; + } + printf(" ---> Total budgets \n"); printf(" Radiation Omega = %-15g , omega = %-15g \n",budget_radiation,budget_radiation*pba->h*pba->h); printf(" Non-relativistic Omega = %-15g , omega = %-15g \n",budget_matter,budget_matter*pba->h*pba->h); @@ -2996,3 +3450,23 @@ double ddV_scf( double phi) { return ddV_e_scf(pba,phi)*V_p_scf(pba,phi) + 2*dV_e_scf(pba,phi)*dV_p_scf(pba,phi) + V_e_scf(pba,phi)*ddV_p_scf(pba,phi); } + + +/* NEDE: Here we implement out trigger potential (a simple quadratic) and its derivatives */ +double V_trigger( + struct background *pba, + double phi) { + return 1./2.*pba->NEDE_trigger_mass*pba->NEDE_trigger_mass*phi*phi; +} + +double dV_trigger( + struct background *pba, + double phi) { + return pba->NEDE_trigger_mass*pba->NEDE_trigger_mass*phi; +} + +double ddV_trigger( + struct background *pba, + double phi) { + return pba->NEDE_trigger_mass*pba->NEDE_trigger_mass; +} diff --git a/source/input.c b/source/input.c index c376d1d8a..278b66903 100644 --- a/source/input.c +++ b/source/input.c @@ -420,13 +420,17 @@ int input_read_from_file(struct file_content * pfc, errmsg), errmsg, errmsg); + + /** Update structs with input that is potentially updated after shooting */ + class_call(input_read_parameters(pfc,ppr,pba,pth,ppt,ptr,ppm,phr,pfo,ple,psd,pop, + errmsg), + errmsg, + errmsg); - /** If no shooting is necessary, initialize read parameters without it */ - if (has_shooting == _FALSE_){ - class_call(input_read_parameters(pfc,ppr,pba,pth,ppt,ptr,ppm,phr,pfo,ple,psd,pop, - errmsg), - errmsg, - errmsg); + if (has_shooting == _TRUE_ && pba->shooting_failed == _TRUE_) { + // Shooting failed, but error must be thrown in background in order to trigger a + // runtime error, so here we skip the rest and go straight to background + return _SUCCESS_; } /** Write info on the read/unread parameters. This is the correct place to do it, @@ -512,7 +516,7 @@ int input_shooting(struct file_content * pfc, double param1, param2; double * unknown_parameter; int unknown_parameters_size; - int counter, index_target, i; + int counter, index_target; int fevals=0; double xzero; double *dxdF, *x_inout; @@ -527,7 +531,10 @@ int input_shooting(struct file_content * pfc, "omega_dcdmdr", "Omega_scf", "Omega_ini_dcdm", - "omega_ini_dcdm"}; + "omega_ini_dcdm", + "z_decay_NEDE", + "Omega0_NEDE_trigger_DM", + "NEDE_trigger_ini"}; /* array of corresponding parameters that must be adjusted in order to meet the target (= unknown parameters) */ char * const unknown_namestrings[] = {"h", /* unknown param for target '100*theta_s' */ @@ -536,7 +543,10 @@ int input_shooting(struct file_content * pfc, "omega_ini_dcdm", /* unknown param for target 'omega_dcdmdr' */ "scf_shooting_parameter", /* unknown param for target 'Omega_scf' */ "Omega_dcdmdr", /* unknown param for target 'Omega_ini_dcdm' */ - "omega_dcdmdr"}; /* unknown param for target 'omega_ini_dcdm' */ + "omega_dcdmdr", /* unknown param for target 'omega_ini_dcdm' */ + "NEDE_trigger_mass", /* unknown param for target 'z_decay_NEDE' */ + "NEDE_trigger_ini", /* unknown param for target 'Omega0_NEDE_trigger_DM' */ + "Omega0_NEDE_trigger_DM"}; /* unknown param for target 'NEDE_trigger_ini' */ /* for each target, module up to which we need to run CLASS in order to compute the targetted quantities (not running the whole code @@ -547,7 +557,10 @@ int input_shooting(struct file_content * pfc, cs_background, /* computation stage for target 'omega_dcdmdr' */ cs_background, /* computation stage for target 'Omega_scf' */ cs_background, /* computation stage for target 'Omega_ini_dcdm' */ - cs_background}; /* computation stage for target 'omega_ini_dcdm' */ + cs_background, /* computation stage for target 'omega_ini_dcdm' */ + cs_background, /* computation stage for target 'z_decay_NEDE' */ + cs_background, /* computation stage for target 'Omega0_NEDE_trigger_DM' */ + cs_background}; /* computation stage for target 'NEDE_trigger_ini' */ struct fzerofun_workspace fzw; @@ -557,6 +570,7 @@ int input_shooting(struct file_content * pfc, unknown_parameters_size = 0; fzw.required_computation_stage = 0; for (index_target = 0; index_target < _NUM_TARGETS_; index_target++){ + class_call(parser_read_double(pfc,target_namestrings[index_target],¶m1,&flag1,errmsg), errmsg, errmsg); @@ -586,17 +600,11 @@ int input_shooting(struct file_content * pfc, /* We need to remember that we shot so we can clean up properly */ *has_shooting=_TRUE_; - /* Create file content structure with additional entries */ - class_call(parser_init(&(fzw.fc), - pfc->size+unknown_parameters_size, - pfc->filename, - errmsg), + class_call(parser_extend(pfc, unknown_parameters_size, errmsg), errmsg,errmsg); - /* Copy input file content to the new file content structure: */ - memcpy(fzw.fc.name, pfc->name, pfc->size*sizeof(FileArg)); - memcpy(fzw.fc.value, pfc->value, pfc->size*sizeof(FileArg)); - memcpy(fzw.fc.read, pfc->read, pfc->size*sizeof(short)); + class_call(parser_init_from_pfc(pfc, &(fzw.fc), errmsg), + errmsg,errmsg); class_alloc(unknown_parameter, unknown_parameters_size*sizeof(double), @@ -628,7 +636,7 @@ int input_shooting(struct file_content * pfc, fzw.target_name[counter] = index_target; /* store target value of target parameter */ fzw.target_value[counter] = param1; - fzw.unknown_parameters_index[counter]=pfc->size+counter; + fzw.unknown_parameters_index[counter]=pfc->size+counter-unknown_parameters_size; /* substitute the name of the target parameter with the name of the corresponding unknown parameter */ strcpy(fzw.fc.name[fzw.unknown_parameters_index[counter]],unknown_namestrings[index_target]); @@ -723,32 +731,14 @@ int input_shooting(struct file_content * pfc, fprintf(stdout,"Shooting completed using %d function evaluations\n",fevals); } - /** Read all parameters from the fc obtained through shooting */ - class_call(input_read_parameters(&(fzw.fc),ppr,pba,pth,ppt,ptr,ppm,phr,pfo,ple,psd,pop, - errmsg), - errmsg, - errmsg); - /** Set status of shooting */ pba->shooting_failed = shooting_failed; - if (pba->shooting_failed == _TRUE_) { - background_free_input(pba); - thermodynamics_free_input(pth); - perturbations_free_input(ppt); - } - /* all parameters read in fzw must be considered as read in pfc. At the same - time the parameters read before in pfc (like theta_s,...) must still be - considered as read (hence we could not do a memcopy) */ - for (i=0; i < pfc->size; i ++) { - if (fzw.fc.read[i] == _TRUE_) - pfc->read[i] = _TRUE_; - } - - /* Free tuned pfc */ - parser_free(&(fzw.fc)); + parser_copy(&(fzw.fc), pfc, pfc->size - unknown_parameters_size, pfc->size); /** Free arrays allocated */ + class_call(parser_free(&(fzw.fc)), + errmsg, errmsg); free(unknown_parameter); free(fzw.unknown_parameters_index); free(fzw.target_name); @@ -769,17 +759,12 @@ int input_shooting(struct file_content * pfc, if (flag1 == _TRUE_ || flag2 == _TRUE_) { /* Tell the main function that shooting indeed has occured */ *has_shooting=_TRUE_; - /* Create file content structure with additional entries */ - class_call(parser_init(&(fzw.fc), - pfc->size+1, - pfc->filename, - errmsg), - errmsg,errmsg); - /* Copy input file content to the new file content structure: */ - memcpy(fzw.fc.name, pfc->name, pfc->size*sizeof(FileArg)); - memcpy(fzw.fc.value, pfc->value, pfc->size*sizeof(FileArg)); - memcpy(fzw.fc.read, pfc->read, pfc->size*sizeof(short)); + class_call(parser_extend(pfc, 1, errmsg), + errmsg,errmsg); + + class_call(parser_init_from_pfc(pfc, &(fzw.fc), errmsg), + errmsg,errmsg); fzw.target_size = 1; class_alloc(fzw.unknown_parameters_index, @@ -802,11 +787,11 @@ int input_shooting(struct file_content * pfc, fzw.target_value[0] = param2; } /* store target value of target parameter */ - fzw.unknown_parameters_index[0]=pfc->size; + fzw.unknown_parameters_index[0]=pfc->size - 1; fzw.required_computation_stage = cs_nonlinear; /* substitute the name of the target parameter with the name of the corresponding unknown parameter */ - strcpy(fzw.fc.name[pfc->size],"A_s"); + strcpy(fzw.fc.name[pfc->size - 1],"A_s"); /* Print to the user */ if (input_verbose > 0) { @@ -838,30 +823,18 @@ int input_shooting(struct file_content * pfc, A_s = (fzw.target_value[0]/sigma8_or_S8) *(fzw.target_value[0]/sigma8_or_S8) * A_s; //(truesigma/sigma_for_guess)^2 *A_s_for_guess /* Store the derived value with high enough accuracy */ - sprintf(fzw.fc.value[pfc->size],"%.20e",A_s); + sprintf(fzw.fc.value[pfc->size - 1],"%.20e",A_s); if (input_verbose > 0) { fprintf(stdout," -> found '%s = %s'\n", - fzw.fc.name[pfc->size], - fzw.fc.value[pfc->size]); + fzw.fc.name[pfc->size - 1], + fzw.fc.value[pfc->size - 1]); } - - /* Now read the remaining parameters from the fine tuned fzw into the individual structures */ - class_call(input_read_parameters(&(fzw.fc),ppr,pba,pth,ppt,ptr,ppm,phr,pfo,ple,psd,pop, - errmsg), - errmsg, - errmsg); - - /* all parameters read in fzw must be considered as read in pfc. At the same - time the parameters read before in pfc (like theta_s,...) must still be - considered as read (hence we could not do a memcopy) */ - for (i=0; i < pfc->size; i ++) { - if (fzw.fc.read[i] == _TRUE_) - pfc->read[i] = _TRUE_; - } - - /* Free tuned pfc */ - parser_free(&(fzw.fc)); + + parser_copy(&(fzw.fc), pfc, pfc->size - 1, pfc->size); + /** Free arrays allocated */ + class_call(parser_free(&(fzw.fc)), + errmsg, errmsg); /** Free arrays allocated */ free(fzw.unknown_parameters_index); free(fzw.target_name); @@ -1282,6 +1255,37 @@ int input_get_guess(double *xguess, xguess[index_guess] = 2.43e-9/0.891*pfzw->target_value[index_guess]; dxdy[index_guess] = 2.43e-9/0.891; break; + case z_decay_NEDE: { + // Need to guess NEDE_trigger_mass + double Omega_M = ba.Omega0_cdm + ba.Omega0_b + ba.Omega0_ncdm_tot; + double z_NEDE = pfzw->target_value[index_guess]; + double trigger_mass = 0.5 * ba.H0 / ba.Bubble_trigger_H_over_m * pow(1. / (1. - ba.f_NEDE), 0.5) * pow(Omega_M * pow((1. + z_NEDE), 3) + Omega_M * pow((1. + z_NEDE), 4) / (3001.) + (1. - Omega_M), 0.5); + + xguess[index_guess] = trigger_mass; + dxdy[index_guess] = 0.5 * trigger_mass * (3. * Omega_M * pow((1. + z_NEDE), 2) + 4. * Omega_M * pow((1. + z_NEDE), 3) / (3001.)) / (Omega_M * pow((1. + z_NEDE), 3) + Omega_M * pow((1. + z_NEDE), 4) / (3001.) + (1. - Omega_M)); + break; + } + case Omega0_NEDE_trigger_DM: { + // Need to guess NEDE_trigger_ini + double Omega_M = ba.Omega0_cdm + ba.Omega0_b + ba.Omega0_ncdm_tot; + double z_NEDE = ba.z_decay_NEDE; + double trigger_mass = 0.5 * ba.H0 / ba.Bubble_trigger_H_over_m * pow(1. / (1. - ba.f_NEDE), 0.5) * pow(Omega_M * pow((1. + z_NEDE), 3) + Omega_M * pow((1. + z_NEDE), 4) / (3001.) + (1. - Omega_M), 0.5); + + xguess[index_guess] = 0.5*pow(75. * ba.H0 * ba.H0 * pfzw->target_value[index_guess] * pow(z_NEDE, 3) / pow(trigger_mass, 2), 0.5); + dxdy[index_guess] = 0.5 * xguess[index_guess] / pfzw->target_value[index_guess]; + break; + } + case NEDE_trigger_ini: { + // Need to guess Omega0_NEDE_trigger_DM + // Inversion of the guess above + double Omega_M = ba.Omega0_cdm + ba.Omega0_b + ba.Omega0_ncdm_tot; + double z_NEDE = ba.z_decay_NEDE; + double trigger_mass = 0.5 * ba.H0 / ba.Bubble_trigger_H_over_m * pow(1. / (1. - ba.f_NEDE), 0.5) * pow(Omega_M * pow((1. + z_NEDE), 3) + Omega_M * pow((1. + z_NEDE), 4) / (3001.) + (1. - Omega_M), 0.5); + + xguess[index_guess] = pow(pfzw->target_value[index_guess]*trigger_mass/ba.H0, 2.)/(75.*pow(z_NEDE, 3.)); + dxdy[index_guess] = 2.*pfzw->target_value[index_guess]*pow(trigger_mass/ba.H0, 2.)/(75.*pow(z_NEDE, 3.)); // derivative of xguess + break; + } } } @@ -1493,6 +1497,44 @@ int input_try_unknown_parameters(double * unknown_parameter, case S8: output[i] = fo.sigma8[fo.index_pk_m]*sqrt(ba.Omega0_m/0.3); break; + case z_decay_NEDE: { + double z_decay = 0.; + double H_decay = ba.NEDE_trigger_mass*ba.Bubble_trigger_H_over_m; + for (int index_tau = 1; index_tau < ba.bt_size - 1; ++index_tau) { + double H_z = ba.background_table[index_tau*ba.bg_size + ba.index_bg_H]; + if (H_decay > H_z) { + /* Linear interpolation to find approximate decay redshift */ + double a1 = ba.background_table[(index_tau - 1)*ba.bg_size + ba.index_bg_a]; + double a2 = ba.background_table[index_tau*ba.bg_size + ba.index_bg_a]; + double H1 = ba.background_table[(index_tau - 1)*ba.bg_size + ba.index_bg_H]; + double H2 = ba.background_table[index_tau*ba.bg_size + ba.index_bg_H]; + double a_decay = a1 + (H_decay - H1)*(a2 - a1)/(H2 - H1); + z_decay = 1./a_decay - 1.; + break; + } + } + + output[i] = z_decay - pfzw->target_value[i]; + if (input_verbose > 1) { + printf("z_decay=%f, target=%f\n", z_decay, pfzw->target_value[i]); + } + break; + } + case Omega0_NEDE_trigger_DM: { + output[i] = ba.Omega0_trigger - pfzw->target_value[i]; + if (input_verbose > 1) { + printf("Omega0_NEDE_trigger_DM=%f, target=%f\n", ba.Omega0_trigger, pfzw->target_value[i]); + } + break; + } + case NEDE_trigger_ini: { + double Omega0_trigger_today = ba.background_table[(ba.bt_size-1)*ba.bg_size+ba.index_bg_rho_trigger]/ba.H0/ba.H0; + output[i] = ba.Omega0_trigger - Omega0_trigger_today; + if (input_verbose > 1) { + printf("NEDE_trigger_ini=%f, target=%f\n", ba.NEDE_trigger_ini, pfzw->target_value[i]); + } + break; + } } } @@ -2340,6 +2382,10 @@ int input_read_parameters_species(struct file_content * pfc, int flag1, flag2, flag3; double param1, param2, param3; char string1[_ARGUMENT_LENGTH_MAX_]; + + int flag_NEDE, flag_NEDE_4; + char string_NEDE[_ARGUMENT_LENGTH_MAX_]; + int fileentries; int N_ncdm=0, n, entries_read; double rho_ncdm; @@ -3127,6 +3173,100 @@ int input_read_parameters_species(struct file_content * pfc, printf("Warning: Setting the tight_coupling_approximation = compromise_CLASS, since you selected idm-g!\n"); ppr->tight_coupling_approximation = compromise_CLASS; } + + /** 7.3) New Early Dark Energy */ + class_read_double("f_NEDE", pba->f_NEDE); + class_read_double("z_decay_NEDE", pba->z_decay_NEDE); /* Related by shooting */ + class_read_double("NEDE_trigger_mass", pba->NEDE_trigger_mass); /* */ + class_read_double("three_eos_NEDE", pba->three_eos_NEDE); + class_read_double("three_ceff2_NEDE", ppt->three_ceff2_NEDE); + class_read_double("three_cvis2_NEDE", ppt->three_cvis2_NEDE); + class_read_double("H_over_m_NEDE", pba->Bubble_trigger_H_over_m); + class_read_double("Junction_tag", pba->Junction_tag); + class_read_double("Omega0_NEDE", pba->Omega0_NEDE); // Omega today, is only used internally, when finding a better fit for z_decay. + class_read_double("NEDE_trigger_ini", pba->NEDE_trigger_ini); /* Related by shooting */ + class_read_double("Omega0_NEDE_trigger_DM", pba->Omega0_trigger); /* */ + + /* NEDE: Here we decide whether NEDE decays according to scenario A or B. Default: Scneario A*/ + + class_call(parser_read_string(pfc, "NEDE_fld_nature", &string_NEDE, &flag_NEDE_4, errmsg), + errmsg, + errmsg); + + if (flag_NEDE_4 == _TRUE_) + { + if ((strstr(string_NEDE, "A") != NULL) || (strstr(string1, "stiff") != NULL) || (strstr(string1, "Scenario_A") != NULL) || (strstr(string1, "const") != NULL)) + { + pba->NEDE_fld_nature = NEDE_fld_A; + } + if ((strstr(string_NEDE, "B") != NULL) || (strstr(string1, "decay") != NULL) || (strstr(string1, "Scenario_B") != NULL)) + { + pba->NEDE_fld_nature = NEDE_fld_B; + } + } + + // Decide if the effective sound speed is tracking the adiabatic sound speed. Default: no tracking (constant) + class_call(parser_read_string(pfc, "NEDE_ceff_nature", &string_NEDE, &flag_NEDE, errmsg), + errmsg, + errmsg); + + if (flag_NEDE == _TRUE_) + { + if ((strstr(string_NEDE, "constant") != NULL) || (strstr(string1, "Constant") != NULL) || (strstr(string1, "CONSTANT") != NULL) || (strstr(string1, "const") != NULL)) + { + ppt->NEDE_ceff_nature = NEDE_ceff_const; + } + if ((strstr(string_NEDE, "tracking") != NULL) || (strstr(string1, "Tracking") != NULL) || (strstr(string1, "TRACKING") != NULL)) + { + ppt->NEDE_ceff_nature = NEDE_ceff_tracking; + } + if ((strstr(string_NEDE, "twice linear") != NULL) || (strstr(string1, "Twice linear") != NULL) || (strstr(string1, "twice") != NULL)) + { + ppt->NEDE_ceff_nature = NEDE_ceff_twice_linear; + flag1 = 0; + flag2 = 0; + flag3 = 0; + int flag4 = 0; + class_call(parser_read_double(pfc,"NEDE_cs2_slope_1",&ppt->NEDE_cs2_slope_1,&flag1,errmsg), + errmsg, + errmsg); + class_call(parser_read_double(pfc,"NEDE_cs2_intercept_1",&ppt->NEDE_cs2_intercept_1,&flag2,errmsg), + errmsg, + errmsg); + class_call(parser_read_double(pfc,"NEDE_cs2_slope_2",&ppt->NEDE_cs2_slope_2,&flag3,errmsg), + errmsg, + errmsg); + class_call(parser_read_double(pfc,"NEDE_cs2_intercept_2",&ppt->NEDE_cs2_intercept_2,&flag4,errmsg), + errmsg, + errmsg); + if (flag1*flag2*flag3*flag4 != 1) { + class_test(_TRUE_, errmsg, "To use the 'twice linear' parametrisation of the NEDE sound speed, you need to input all of the following: NEDE_cs2_slope_1, NEDE_cs2_intercept_1, NEDE_cs2_slope_2, NEDE_cs2_intercept_2.") + } + } + } + + if ((pba->Omega_NEDE > 0) || (pba->f_NEDE > 0)) { + if (pba->Omega_NEDE == 0) + pba->Omega_NEDE = pba->f_NEDE * pow(pba->NEDE_trigger_mass * pba->Bubble_trigger_H_over_m / pba->H0, 2); + else if (pba->f_NEDE == 0) + pba->f_NEDE = pba->Omega_NEDE / pow(pba->NEDE_trigger_mass * pba->Bubble_trigger_H_over_m / pba->H0, 2); + + class_test(pba->z_decay_NEDE == 0, errmsg, + "In input file, z_decay_NEDE needs to be specified for NEDE (The trigger mass as input parameter has been retired in v5)."); + + class_test(((pba->NEDE_trigger_ini == 0.) && (pba->Omega0_trigger == 0.)), errmsg, + "You must input either 'NEDE_trigger_ini' or 'Omega0_NEDE_trigger_DM' to set the trigger density.") + + class_read_double("NEDE_trigger_fluid_H_m", pba->trigger_fluid_H_over_m); + + pba->trigger_fluid_approximation = _FALSE_; + pba->trigger_fluid_safety_factor = 1.05; + pba->phi_prime_ini_trigger = 0; // This value is set to the attractor later. + + if (pba->NEDE_fld_nature == NEDE_fld_A) + pba->Omega0_NEDE = pba->Omega_NEDE * pow(1. / (1. + pba->z_decay_NEDE), (3. + pba->three_eos_NEDE)); + } + /* ** ADDITIONAL SPECIES ** */ @@ -3206,6 +3346,11 @@ int input_read_parameters_species(struct file_content * pfc, Omega_tot += pba->Omega0_dcdmdr; Omega_tot += pba->Omega0_idr; Omega_tot += pba->Omega0_ncdm_tot; + + /* NEDE budget, both zero if no NEDE */ + Omega_tot += pba->Omega0_NEDE; + Omega_tot += pba->Omega0_trigger; + /* Step 1 */ if (flag1 == _TRUE_){ pba->Omega0_lambda = param1; @@ -5485,6 +5630,26 @@ int input_read_parameters_output(struct file_content * pfc, class_read_int("lensing_verbose",ple->lensing_verbose); class_read_int("distortions_verbose",psd->distortions_verbose); class_read_int("output_verbose",pop->output_verbose); + + /** Gauge to plot perturbations in */ + char plot_gauge[_ARGUMENT_LENGTH_MAX_]; + int flag_temp; + parser_read_string(pfc, "plot_gauge", &plot_gauge, &flag_temp, errmsg); + if (flag_temp == _TRUE_) { + if ((strcmp(plot_gauge, "newtonian") == 0) || (strcmp(plot_gauge, "Newtonian") == 0)) { + ppt->plot_gauge = 0; // indexed as in the possible_gauges of perturbations.h + } + else if ((strcmp(plot_gauge, "synchronous") == 0) || (strcmp(plot_gauge, "Synchronous") == 0)) { + ppt->plot_gauge = 1; // indexed as in the possible_gauges of perturbations.h + } + else { + class_test(0 == 0, errmsg, "Invalid input in 'plot_gauges'. Choose either 'newtonian' or 'synchronous'.") + } + } + else { + // Default is Newtonian gauge + ppt->plot_gauge = 0; + } return _SUCCESS_; @@ -5806,6 +5971,28 @@ int input_default_params(struct background *pba, /** 7.2.4.b) temperature scaling idm_g */ pth->n_index_idm_g = 0; ppt->has_idm_soundspeed = _FALSE_; + + /** 7.3) New EDE parameters */ + pba->Omega_trigger_decay = 0.; + pba->three_eos_NEDE = 2.; // Default: w=2/3. + pba->Omega_NEDE = 0.; + pba->f_NEDE = 0; + pba->Omega0_NEDE = 0.; + pba->decay_flag = _FALSE_; // Initially the decay has not yet taken place. + pba->Junction_tag = 1; // Default: standard junction condition inferred from matching. + pba->NEDE_trigger_ini = 0.; + pba->Omega0_trigger = 0.; // Default value + pba->trigger_fluid_H_over_m = 0.; /* Trigger fluid threshold. Default: Never turn on */ + pba->a_trigger_fluid = 100.; /* True iff trigger field fluid approximation is turned on; default is never on */ + + pba->Bubble_trigger_H_over_m = .2; // Default value ionferred from miscroscpic model. + pba->NEDE_trigger_mass = 0.; + pba->z_decay_NEDE = 0.; + + ppt->three_ceff2_NEDE = 2.; // Default: matches adiabatic sound speed. + ppt->three_cvis2_NEDE = 0.; + pba->NEDE_fld_nature = NEDE_fld_A; + ppt->NEDE_ceff_nature = NEDE_ceff_const; /* ** ADDITIONAL SPECIES ** */ diff --git a/source/perturbations.c b/source/perturbations.c index 2d353f389..20e541e09 100644 --- a/source/perturbations.c +++ b/source/perturbations.c @@ -470,6 +470,8 @@ int perturbations_output_data( class_store_double(dataptr,tk[ppt->index_tp_delta_idm],ppt->has_source_delta_idm,storeidx); class_store_double(dataptr,tk[ppt->index_tp_delta_fld],ppt->has_source_delta_fld,storeidx); class_store_double(dataptr,tk[ppt->index_tp_delta_ur],ppt->has_source_delta_ur,storeidx); + class_store_double(dataptr,tk[ppt->index_tp_delta_NEDE],ppt->has_source_delta_NEDE,storeidx); + // class_store_double(dataptr,tk[ppt->index_tp_delta_trigger],ppt->has_source_delta_trigger,storeidx); class_store_double(dataptr,tk[ppt->index_tp_delta_idr],ppt->has_source_delta_idr,storeidx); if (pba->has_ncdm == _TRUE_){ for (n_ncdm = 0; n_ncdm < pba->N_ncdm; n_ncdm++){ @@ -499,6 +501,8 @@ int perturbations_output_data( class_store_double(dataptr,tk[ppt->index_tp_theta_idm],ppt->has_source_theta_idm,storeidx); class_store_double(dataptr,tk[ppt->index_tp_theta_fld],ppt->has_source_theta_fld,storeidx); class_store_double(dataptr,tk[ppt->index_tp_theta_ur],ppt->has_source_theta_ur,storeidx); + class_store_double(dataptr,tk[ppt->index_tp_theta_NEDE],ppt->has_source_theta_NEDE,storeidx); + // class_store_double(dataptr,tk[ppt->index_tp_theta_trigger],ppt->has_source_theta_trigger,storeidx); class_store_double(dataptr,tk[ppt->index_tp_theta_idr],ppt->has_source_theta_idr,storeidx); if (pba->has_ncdm == _TRUE_){ for (n_ncdm = 0; n_ncdm < pba->N_ncdm; n_ncdm++){ @@ -558,6 +562,7 @@ int perturbations_output_titles( class_store_columntitle(titles,"d_idm",pba->has_idm); class_store_columntitle(titles,"d_fld",pba->has_fld); class_store_columntitle(titles,"d_ur",pba->has_ur); + class_store_columntitle(titles,"d_NEDE",pba->has_NEDE_pert); class_store_columntitle(titles,"d_idr",pba->has_idr); if (pba->has_ncdm == _TRUE_) { for (n_ncdm=0; n_ncdm < pba->N_ncdm; n_ncdm++) { @@ -568,6 +573,7 @@ int perturbations_output_titles( class_store_columntitle(titles,"d_dcdm",pba->has_dcdm); class_store_columntitle(titles,"d_dr",pba->has_dr); class_store_columntitle(titles,"d_scf",pba->has_scf); + // class_store_columntitle(titles,"d_trigger",pba->has_NEDE_trigger); class_store_columntitle(titles,"d_m",ppt->has_source_delta_m); class_store_columntitle(titles,"d_tot",ppt->has_source_delta_tot); class_store_columntitle(titles,"phi",ppt->has_source_phi); @@ -587,6 +593,7 @@ int perturbations_output_titles( class_store_columntitle(titles,"t_idm",pba->has_idm); class_store_columntitle(titles,"t_fld",pba->has_fld); class_store_columntitle(titles,"t_ur",pba->has_ur); + class_store_columntitle(titles, "t_NEDE", pba->has_NEDE_pert); class_store_columntitle(titles,"t_idr",pba->has_idr); if (pba->has_ncdm == _TRUE_) { for (n_ncdm=0; n_ncdm < pba->N_ncdm; n_ncdm++) { @@ -597,6 +604,7 @@ int perturbations_output_titles( class_store_columntitle(titles,"t_dcdm",pba->has_dcdm); class_store_columntitle(titles,"t_dr",pba->has_dr); class_store_columntitle(titles,"t_scf",pba->has_scf); + // class_store_columntitle(titles,"t_trigger",pba->has_NEDE_trigger); class_store_columntitle(titles,"t_tot",_TRUE_); } } @@ -742,6 +750,21 @@ int perturbations_init( if (ppt->perturbations_verbose > 0) printf("Computing sources\n"); } + + if (pba->has_NEDE && ppt->perturbations_verbose > 1) { + printf(" -> NEDE perturbation details:\n"); + if (ppt->NEDE_ceff_nature == NEDE_ceff_const) + printf(" -> 3*ceff2: %f (constant)\n", ppt->three_ceff2_NEDE); + else if (ppt->NEDE_ceff_nature == NEDE_ceff_tracking) + printf(" -> ceff2 = ca2 (tracking) \n"); + else if (ppt->NEDE_ceff_nature == NEDE_ceff_twice_linear) + printf(" -> ceff2 = twice linear \n"); + else + printf(" -> ceff2 not understood!\n"); + printf(" -> 3*cvis2: %f (constant) \n", ppt->three_cvis2_NEDE); + printf(" -> Junction_tag: %d \n", pba->Junction_tag); + printf(" -> NEDE sub-dominant condition: %e \n", ppr->sub_dom_cond); + } class_test((ppt->gauge == synchronous) && (pba->has_cdm == _FALSE_), ppt->error_message, @@ -1298,6 +1321,8 @@ int perturbations_indices( ppt->has_source_delta_scf = _FALSE_; ppt->has_source_delta_dr = _FALSE_; ppt->has_source_delta_ur = _FALSE_; + ppt->has_source_delta_NEDE = _FALSE_; + ppt->has_source_delta_trigger = _FALSE_; ppt->has_source_delta_idr = _FALSE_; ppt->has_source_delta_ncdm = _FALSE_; ppt->has_source_delta_tot = _FALSE_; @@ -1313,6 +1338,8 @@ int perturbations_indices( ppt->has_source_theta_scf = _FALSE_; ppt->has_source_theta_dr = _FALSE_; ppt->has_source_theta_ur = _FALSE_; + ppt->has_source_theta_NEDE = _FALSE_; + ppt->has_source_theta_trigger = _FALSE_; ppt->has_source_theta_idr = _FALSE_; ppt->has_source_theta_ncdm = _FALSE_; ppt->has_source_theta_tot = _FALSE_; @@ -1413,6 +1440,11 @@ int perturbations_indices( ppt->has_source_delta_dr = _TRUE_; if (pba->has_ncdm == _TRUE_) ppt->has_source_delta_ncdm = _TRUE_; + if (pba->has_NEDE == _TRUE_) { + ppt->has_source_delta_NEDE = _TRUE_; + ppt->has_source_delta_trigger = _TRUE_; + } + // No source for the subdom trigger field required. // Thanks to the following lines, (phi,psi) are also stored as sources // (Obtained directly in newtonian gauge, infereed from (h,eta) in synchronous gauge). // If density transfer functions are requested in the (default) CLASS format, @@ -1510,6 +1542,7 @@ int perturbations_indices( class_define_index(ppt->index_tp_delta_dcdm, ppt->has_source_delta_dcdm,index_type,1); class_define_index(ppt->index_tp_delta_fld, ppt->has_source_delta_fld, index_type,1); class_define_index(ppt->index_tp_delta_scf, ppt->has_source_delta_scf, index_type,1); + // class_define_index(ppt->index_tp_delta_trigger, ppt->has_source_delta_trigger, index_type,1); class_define_index(ppt->index_tp_delta_dr, ppt->has_source_delta_dr, index_type,1); class_define_index(ppt->index_tp_delta_ur, ppt->has_source_delta_ur, index_type,1); class_define_index(ppt->index_tp_delta_idr, ppt->has_source_delta_idr, index_type,1); @@ -1524,6 +1557,7 @@ int perturbations_indices( class_define_index(ppt->index_tp_theta_dcdm, ppt->has_source_theta_dcdm,index_type,1); class_define_index(ppt->index_tp_theta_fld, ppt->has_source_theta_fld, index_type,1); class_define_index(ppt->index_tp_theta_scf, ppt->has_source_theta_scf, index_type,1); + // class_define_index(ppt->index_tp_theta_trigger, ppt->has_source_theta_trigger, index_type,1); class_define_index(ppt->index_tp_theta_dr, ppt->has_source_theta_dr, index_type,1); class_define_index(ppt->index_tp_theta_ur, ppt->has_source_theta_ur, index_type,1); class_define_index(ppt->index_tp_theta_idr, ppt->has_source_theta_idr, index_type,1); @@ -2866,6 +2900,10 @@ int perturbations_workspace_init( class_define_index(ppw->index_ap_ncdmfa,pba->has_ncdm,index_ap,1); class_define_index(ppw->index_ap_tca_idm_dr,pba->has_idr,index_ap,1); class_define_index(ppw->index_ap_rsa_idr,pba->has_idr,index_ap,1); + + class_define_index(ppw->index_ap_CCa, pba->has_NEDE, index_ap, 1); + class_define_index(ppw->index_ap_sda, pba->has_NEDE, index_ap, 1); + class_define_index(ppw->index_ap_tfa, pba->has_NEDE_trigger, index_ap, 1); } ppw->ap_size=index_ap; @@ -2895,6 +2933,22 @@ int perturbations_workspace_init( if (pba->has_ncdm == _TRUE_) { ppw->approx[ppw->index_ap_ncdmfa]=(int)ncdmfa_off; } + + /*New EDE: Define different evolution phases*/ + if (pba->has_NEDE_pert == _TRUE_) { + /*CCa_on: NEDE is decribed as a constant without fluctuations.*/ + /*CCa_off: NEDE is decribed as a fluid with fluctuations.*/ + ppw->approx[ppw->index_ap_CCa] = (int)CCa_on; + + if (pba->has_NEDE_trigger == _TRUE_) { + ppw->approx[ppw->index_ap_tfa] = (int)tfa_off; + } + } + if (pba->has_NEDE_pert == _TRUE_) { + /*sda_on: NEDE has decayed sufficiently far that we do not need to track its perturbations. As a conservative condition we use that rho_EDE/rho_tot < 10^(-6).*/ + /*sda_off: NEDE is not yet subdominant and we therefore need to track its perturbations.*/ + ppw->approx[ppw->index_ap_sda] = (int)sda_off; + } } if (_tensors_) { @@ -3311,9 +3365,12 @@ int perturbations_solve( if (ppr->evolver == rk){ generic_evolver = evolver_rk; } - else { + else if (ppr->evolver == ndf15){ generic_evolver = evolver_ndf15; } + else if (ppr->evolver == rkdp45) { + generic_evolver = evolver_rkdp45; + } class_call(generic_evolver(perturbations_derivs, interval_limit[index_interval], @@ -3451,6 +3508,14 @@ int perturbations_prepare_k_output(struct background * pba, class_store_columntitle(ppt->scalar_titles, "delta_rho_fld", pba->has_fld); class_store_columntitle(ppt->scalar_titles, "rho_plus_p_theta_fld", pba->has_fld); class_store_columntitle(ppt->scalar_titles, "delta_p_fld", pba->has_fld); + /* NEDE*/ + class_store_columntitle(ppt->scalar_titles, "delta_NEDE", pba->has_NEDE_pert); + class_store_columntitle(ppt->scalar_titles, "theta_NEDE", pba->has_NEDE_pert); + class_store_columntitle(ppt->scalar_titles, "shear_NEDE", pba->has_NEDE_pert); + /* NEDE: Trigger field*/ + class_store_columntitle(ppt->scalar_titles, "delta_trigger", pba->has_NEDE_trigger); + class_store_columntitle(ppt->scalar_titles, "theta_hat_trigger", pba->has_NEDE_trigger); + class_store_columntitle(ppt->scalar_titles, "cs2_trigger", pba->has_NEDE_trigger); ppt->number_of_scalar_titles = get_number_of_titles(ppt->scalar_titles); @@ -3829,6 +3894,19 @@ int perturbations_find_approximation_switches( fprintf(stdout,"Mode k=%e: will switch on ncdm fluid approximation at tau=%e\n",k,interval_limit[index_switch]); } } + if (pba->has_NEDE_pert == _TRUE_) { + /* Here we check when the phase transition has occurred */ + if ((interval_approx[index_switch - 1][ppw->index_ap_CCa] == (int)CCa_on) && + (interval_approx[index_switch][ppw->index_ap_CCa] == (int)CCa_off)) { + fprintf(stdout, "Mode k=%e: will create decaying NEDE mode at tau=%e\n", k, interval_limit[index_switch]); + } + if (pba->has_NEDE_trigger_DM == _TRUE_) { + if ((interval_approx[index_switch - 1][ppw->index_ap_tfa] == (int)tfa_off) && + (interval_approx[index_switch][ppw->index_ap_tfa] == (int)tfa_on)) { + fprintf(stdout, "Mode k=%e: will switch on trigger fluid approximation at tau=%e\n", k, interval_limit[index_switch]); + } + } + } } if (_tensors_) { @@ -4040,6 +4118,31 @@ int perturbations_vector_init( class_define_index(ppv->index_pt_phi_scf,pba->has_scf,index_pt,1); /* scalar field density */ class_define_index(ppv->index_pt_phi_prime_scf,pba->has_scf,index_pt,1); /* scalar field velocity */ + + /* Here we allocate memory for the variables to be integrated depending on NEDE phase */ + if (pba->has_NEDE_pert == _TRUE_) { + if (pba->has_NEDE_trigger == _TRUE_) { + if (pba->has_NEDE_trigger_DM == _TRUE_ && ppw->approx[ppw->index_ap_tfa] == (int)tfa_off) { + /* trigger field density */ + class_define_index(ppv->index_pt_phi_trigger, pba->has_NEDE_trigger, index_pt, 1); + /* trigger field velocity */ + class_define_index(ppv->index_pt_phi_prime_trigger, pba->has_NEDE_trigger, index_pt, 1); + } + else if (pba->has_NEDE_trigger_DM == _TRUE_ && ppw->approx[ppw->index_ap_tfa] == (int)tfa_on) { + class_define_index(ppv->index_pt_delta_trigger_fld, pba->has_NEDE_trigger_DM, index_pt, 1); + class_define_index(ppv->index_pt_theta_trigger_fld, pba->has_NEDE_trigger_DM, index_pt, 1); + } + } + /* NEDE: Only track perturbations in NEDE fluid after decay and before NEDE is highly subdominant */ + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_off) && (ppw->approx[ppw->index_ap_sda] == (int)sda_off)) { + /* NEDE pert density */ + class_define_index(ppv->index_pt_delta_NEDE, _TRUE_, index_pt, 1); + /* NEDE pert velocity */ + class_define_index(ppv->index_pt_theta_NEDE, _TRUE_, index_pt, 1); + /* NEDE pert sehar */ + class_define_index(ppv->index_pt_shear_NEDE, _TRUE_, index_pt, 1); + } + } /* perturbed recombination: the indices are defined once tca is off. */ if ( (ppt->has_perturbed_recombination == _TRUE_) && (ppw->approx[ppw->index_ap_tca] == (int)tca_off) ){ @@ -4374,19 +4477,27 @@ int perturbations_vector_init( "scalar initial conditions assume ur fluid approximation turned off"); } - + + /* NEDE: Check that all modes are being initizalized before the transition */ + if (pba->has_NEDE_pert == _TRUE_) { + class_test(ppw->approx[ppw->index_ap_CCa] == (int)CCa_off, + ppt->error_message, + "scalar initial conditions assume that phase transition in NEDE has not yet occurred"); + if (pba->has_NEDE_trigger == _TRUE_) { + class_test(ppw->approx[ppw->index_ap_sda] == (int)sda_on, + ppt->error_message, + "The tag sda_on should only be set after the transition"); + } + } + if (pba->has_ncdm == _TRUE_) { - class_test(ppw->approx[ppw->index_ap_ncdmfa] == (int)ncdmfa_on, ppt->error_message, "scalar initial conditions assume ncdm fluid approximation turned off"); - } - class_test(ppw->approx[ppw->index_ap_tca] == (int)tca_off, ppt->error_message, "scalar initial conditions assume tight-coupling approximation turned on"); - } if (_tensors_) { @@ -4614,6 +4725,45 @@ int perturbations_vector_init( } } } + + /*New EDE*/ + /*NEDE and trigger perturbations not affectecd by tight coupling approximation, so we just copy the values from the previous integration step.*/ + + if (pba->has_NEDE_pert == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + ppv->y[ppv->index_pt_delta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_delta_NEDE]; + + ppv->y[ppv->index_pt_theta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_theta_NEDE]; + + ppv->y[ppv->index_pt_shear_NEDE] = + ppw->pv->y[ppw->pv->index_pt_shear_NEDE]; + } + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + + ppv->y[ppv->index_pt_phi_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + + ppv->y[ppv->index_pt_phi_prime_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + } + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + + ppv->y[ppv->index_pt_delta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_delta_trigger_fld]; + + ppv->y[ppv->index_pt_theta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + } /* perturbed recombination */ /* the initial conditions are set when tca is switched off (current block) */ @@ -4683,6 +4833,44 @@ int perturbations_vector_init( } } } + + /*New EDE*/ + /*NEDE and trigger perturbations not affectecd by radiation streaming approximation, so we just copy the values from the previous integration step.*/ + if (pba->has_NEDE_pert == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + ppv->y[ppv->index_pt_delta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_delta_NEDE]; + + ppv->y[ppv->index_pt_theta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_theta_NEDE]; + + ppv->y[ppv->index_pt_shear_NEDE] = + ppw->pv->y[ppw->pv->index_pt_shear_NEDE]; + } + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + + ppv->y[ppv->index_pt_phi_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + + ppv->y[ppv->index_pt_phi_prime_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + } + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + + ppv->y[ppv->index_pt_delta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_delta_trigger_fld]; + + ppv->y[ppv->index_pt_theta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + } } /* -- case of switching on ur fluid @@ -4793,6 +4981,43 @@ int perturbations_vector_init( } } } + /*New EDE*/ + /*EDE and trigger perturbations not affectecd by ur fluid approximation, so we just copy the values from the previous integration step.*/ + if (pba->has_NEDE_pert == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + ppv->y[ppv->index_pt_delta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_delta_NEDE]; + + ppv->y[ppv->index_pt_theta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_theta_NEDE]; + + ppv->y[ppv->index_pt_shear_NEDE] = + ppw->pv->y[ppw->pv->index_pt_shear_NEDE]; + } + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + + ppv->y[ppv->index_pt_phi_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + + ppv->y[ppv->index_pt_phi_prime_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + } + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + + ppv->y[ppv->index_pt_delta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_delta_trigger_fld]; + + ppv->y[ppv->index_pt_theta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + } } } @@ -4887,7 +5112,43 @@ int perturbations_vector_init( } } } + /*New EDE*/ + /*NEDE and trigger perturbations not affectecd by this approximation, so we just copy the values from the previous integration step.*/ + if (pba->has_NEDE_pert == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + ppv->y[ppv->index_pt_delta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_delta_NEDE]; + + ppv->y[ppv->index_pt_theta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_theta_NEDE]; + + ppv->y[ppv->index_pt_shear_NEDE] = + ppw->pv->y[ppw->pv->index_pt_shear_NEDE]; + } + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + + ppv->y[ppv->index_pt_phi_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + + ppv->y[ppv->index_pt_phi_prime_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + } + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + + ppv->y[ppv->index_pt_delta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_delta_trigger_fld]; + ppv->y[ppv->index_pt_theta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + } } } @@ -4999,6 +5260,44 @@ int perturbations_vector_init( } } } + /*New EDE*/ + /*NEDE and trigger perturbations not affectecd by ur fluid approximation, so we just copy the values from the previous integration step.*/ + if (pba->has_NEDE_pert == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + ppv->y[ppv->index_pt_delta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_delta_NEDE]; + + ppv->y[ppv->index_pt_theta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_theta_NEDE]; + + ppv->y[ppv->index_pt_shear_NEDE] = + ppw->pv->y[ppw->pv->index_pt_shear_NEDE]; + } + + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + + ppv->y[ppv->index_pt_phi_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + + ppv->y[ppv->index_pt_phi_prime_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + } + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + + ppv->y[ppv->index_pt_delta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_delta_trigger_fld]; + + ppv->y[ppv->index_pt_theta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + } } } @@ -5064,87 +5363,707 @@ int perturbations_vector_init( ppv->y[ppv->index_pt_delta_ur] = ppw->pv->y[ppw->pv->index_pt_delta_ur]; - ppv->y[ppv->index_pt_theta_ur] = - ppw->pv->y[ppw->pv->index_pt_theta_ur]; + ppv->y[ppv->index_pt_theta_ur] = + ppw->pv->y[ppw->pv->index_pt_theta_ur]; + + ppv->y[ppv->index_pt_shear_ur] = + ppw->pv->y[ppw->pv->index_pt_shear_ur]; + + if (ppw->approx[ppw->index_ap_ufa] == (int)ufa_off) { + + ppv->y[ppv->index_pt_l3_ur] = + ppw->pv->y[ppw->pv->index_pt_l3_ur]; + + for (l=4; l <= ppv->l_max_ur; l++) + ppv->y[ppv->index_pt_delta_ur+l] = + ppw->pv->y[ppw->pv->index_pt_delta_ur+l]; + + } + } + } + + /*New EDE*/ + /*NEDE and trigger perturbations not affectecd by ncdm fluid approximation, so we just copy the values from the previous integration step.*/ + if (pba->has_NEDE_pert == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + ppv->y[ppv->index_pt_delta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_delta_NEDE]; + + ppv->y[ppv->index_pt_theta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_theta_NEDE]; + + ppv->y[ppv->index_pt_shear_NEDE] = + ppw->pv->y[ppw->pv->index_pt_shear_NEDE]; + } + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + + ppv->y[ppv->index_pt_phi_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + + ppv->y[ppv->index_pt_phi_prime_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + } + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + + ppv->y[ppv->index_pt_delta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_delta_trigger_fld]; + + ppv->y[ppv->index_pt_theta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + } + + if (pba->has_idr == _TRUE_){ + if (ppw->approx[ppw->index_ap_rsa_idr] == (int)rsa_idr_off){ + + ppv->y[ppv->index_pt_delta_idr] = + ppw->pv->y[ppw->pv->index_pt_delta_idr]; + + ppv->y[ppv->index_pt_theta_idr] = + ppw->pv->y[ppw->pv->index_pt_theta_idr]; + + if (ppt->idr_nature == idr_free_streaming){ + + if (ppw->approx[ppw->index_ap_tca_idm_dr] == (int)tca_idm_dr_off){ + + ppv->y[ppv->index_pt_shear_idr] = + ppw->pv->y[ppw->pv->index_pt_shear_idr]; + + ppv->y[ppv->index_pt_l3_idr] = + ppw->pv->y[ppw->pv->index_pt_l3_idr]; + + for (l=4; l <= ppv->l_max_idr; l++) + ppv->y[ppv->index_pt_delta_idr+l] = + ppw->pv->y[ppw->pv->index_pt_delta_idr+l]; + } + } + } + } + + a = ppw->pvecback[pba->index_bg_a]; + index_pt = ppw->pv->index_pt_psi0_ncdm1; + for (n_ncdm = 0; n_ncdm < ppv->N_ncdm; n_ncdm++){ + // We are in the fluid approximation, so ncdm_l_size is always 3. + ncdm_l_size = ppv->l_max_ncdm[n_ncdm]+1; + rho_plus_p_ncdm = ppw->pvecback[pba->index_bg_rho_ncdm1+n_ncdm]+ + ppw->pvecback[pba->index_bg_p_ncdm1+n_ncdm]; + for (l=0; l<=2; l++){ + ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+l] = 0.0; + } + factor = pba->factor_ncdm[n_ncdm]/pow(a,4); + for (index_q=0; index_q < ppw->pv->q_size_ncdm[n_ncdm]; index_q++){ + // Integrate over distributions: + q = pba->q_ncdm[n_ncdm][index_q]; + q2 = q*q; + epsilon = sqrt(q2+a*a*pba->M_ncdm[n_ncdm]*pba->M_ncdm[n_ncdm]); + ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm] += + pba->w_ncdm[n_ncdm][index_q]*q2*epsilon* + ppw->pv->y[index_pt]; + + ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+1] += + pba->w_ncdm[n_ncdm][index_q]*q2*q* + ppw->pv->y[index_pt+1]; + + ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+2] += + pba->w_ncdm[n_ncdm][index_q]*q2*q2/epsilon* + ppw->pv->y[index_pt+2]; + + //Jump to next momentum bin in ppw->pv->y: + index_pt += (ppw->pv->l_max_ncdm[n_ncdm]+1); + } + ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm] *=factor/ppw->pvecback[pba->index_bg_rho_ncdm1+n_ncdm]; + ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+1] *=k*factor/rho_plus_p_ncdm; + ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+2] *=2.0/3.0*factor/rho_plus_p_ncdm; + } + } + } + + /*New EDE*/ + /*Here we set the initial conditions for all our NEDE fluid modes / note that all other sectors are unaffected. */ + if (pba->has_NEDE_pert == _TRUE_) + { + if ((pa_old[ppw->index_ap_CCa] == (int)CCa_on) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + + if (ppt->perturbations_verbose > 2) + fprintf(stdout, "Mode k=%e: initialize decaying EDE mode at tau=%e\n", k, tau); + + if (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off) + { + + ppv->y[ppv->index_pt_delta_g] = + ppw->pv->y[ppw->pv->index_pt_delta_g]; + + ppv->y[ppv->index_pt_theta_g] = + ppw->pv->y[ppw->pv->index_pt_theta_g]; + } + + if ((ppw->approx[ppw->index_ap_tca] == (int)tca_off) && (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off)) + { + + ppv->y[ppv->index_pt_shear_g] = + ppw->pv->y[ppw->pv->index_pt_shear_g]; + + ppv->y[ppv->index_pt_l3_g] = + ppw->pv->y[ppw->pv->index_pt_l3_g]; + + for (l = 4; l <= ppw->pv->l_max_g; l++) + { + + ppv->y[ppv->index_pt_delta_g + l] = + ppw->pv->y[ppw->pv->index_pt_delta_g + l]; + } + + ppv->y[ppv->index_pt_pol0_g] = + ppw->pv->y[ppw->pv->index_pt_pol0_g]; + + ppv->y[ppv->index_pt_pol1_g] = + ppw->pv->y[ppw->pv->index_pt_pol1_g]; + + ppv->y[ppv->index_pt_pol2_g] = + ppw->pv->y[ppw->pv->index_pt_pol2_g]; + + ppv->y[ppv->index_pt_pol3_g] = + ppw->pv->y[ppw->pv->index_pt_pol3_g]; + + for (l = 4; l <= ppw->pv->l_max_pol_g; l++) + { + + ppv->y[ppv->index_pt_pol0_g + l] = + ppw->pv->y[ppw->pv->index_pt_pol0_g + l]; + } + } + + if (pba->has_ur == _TRUE_) + { + + if (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off) + { + + ppv->y[ppv->index_pt_delta_ur] = + ppw->pv->y[ppw->pv->index_pt_delta_ur]; + + ppv->y[ppv->index_pt_theta_ur] = + ppw->pv->y[ppw->pv->index_pt_theta_ur]; + + ppv->y[ppv->index_pt_shear_ur] = + ppw->pv->y[ppw->pv->index_pt_shear_ur]; + + if (ppw->approx[ppw->index_ap_ufa] == (int)ufa_off) + { + + ppv->y[ppv->index_pt_l3_ur] = + ppw->pv->y[ppw->pv->index_pt_l3_ur]; + + for (l = 4; l <= ppv->l_max_ur; l++) + ppv->y[ppv->index_pt_delta_ur + l] = + ppw->pv->y[ppw->pv->index_pt_delta_ur + l]; + } + } + } + + if (pba->has_idr == _TRUE_) + { + + if (ppw->approx[ppw->index_ap_rsa_idr] == (int)rsa_idr_off) + { + + ppv->y[ppv->index_pt_delta_idr] = + ppw->pv->y[ppw->pv->index_pt_delta_idr]; + + ppv->y[ppv->index_pt_theta_idr] = + ppw->pv->y[ppw->pv->index_pt_theta_idr]; + + if (ppt->idr_nature == idr_free_streaming) + { + + if ((ppt->has_idm_dr == _FALSE_) || ((ppt->has_idm_dr == _TRUE_) && (ppw->approx[ppw->index_ap_tca_idm_dr] == (int)tca_idm_dr_off))) + { + + ppv->y[ppv->index_pt_shear_idr] = + ppw->pv->y[ppw->pv->index_pt_shear_idr]; + + ppv->y[ppv->index_pt_l3_idr] = + ppw->pv->y[ppw->pv->index_pt_l3_idr]; + + for (l = 4; l <= ppv->l_max_idr; l++) + ppv->y[ppv->index_pt_delta_idr + l] = + ppw->pv->y[ppw->pv->index_pt_delta_idr + l]; + } + } + } + } + + /*New EDE*/ /*important*/ + /*Here, we set the matching conditions for EDE perturbations: before transition perturbations are zero and after transition they start with value set by fluctuation in transition surface / see Israel's equations in our paper*/ + + /*Nothing needs to be done if NEDE is exremly subdominant*/ + if (ppw->approx[ppw->index_ap_sda] == (int)sda_off) + { + a = ppw->pvecback[pba->index_bg_a]; + double a_prime_over_a = ppw->pvecback[pba->index_bg_H] * a; + double w_NEDE, dw_over_da_NEDE; + double delta_phi_over_phi_prime, amp_rel, sigma_NEDE; + + class_call(background_quantities_NEDE(pba, a, a_prime_over_a, NULL, NULL, &w_NEDE, &dw_over_da_NEDE, NULL), + pba->error_message, + pba->error_message); + + if (pba->has_NEDE_trigger == _TRUE_) + delta_phi_over_phi_prime = ppw->pv->y[ppw->pv->index_pt_phi_trigger] / (ppw->pvecback[pba->index_bg_phi_prime_trigger]); + else + delta_phi_over_phi_prime = 0; // In absence of scalar field we use trivial junction conditions as there is no better choice available. This case is not used. + + if (pba->Junction_tag == 0) + { + // Here we use trivial mathcing conditions only to study their relevance. Not used for NEDE runs. + amp_rel = 0.0; + sigma_NEDE = 0.0; + } + else if (pba->Junction_tag == 1) + { + // standard case for NEDE + amp_rel = 1.; + sigma_NEDE = 0.0; + } + else { + class_stop(ppt->error_message, "Junction tag value not understood.") + } + + // printf("k: %f, aH: %f, h': %f, eta': %f, alpha1: %f, alpha2: %f \n",k,a_prime_over_a ,ppw->pvecmetric[ppw->index_mt_h_prime],ppw->pvecmetric[ppw->index_mt_eta_prime],(ppw->pvecmetric[ppw->index_mt_h_prime] + 6.0*ppw->pvecmetric[ppw->index_mt_eta_prime])/(2.0 *k*k),ppw->pvecmetric[ppw->index_mt_alpha]); + + /* Junction conditions, derived in 2006.06686*/ + ppv->y[ppv->index_pt_delta_NEDE] = -(3. + 3. * w_NEDE) * amp_rel * a_prime_over_a * delta_phi_over_phi_prime; + + ppv->y[ppv->index_pt_theta_NEDE] = -1. / (3. + 3. * w_NEDE) * k * k / a_prime_over_a * ppv->y[ppv->index_pt_delta_NEDE]; + // if (k<0.04 && k>0.03) + // printf("v1: %f, v2: %f, v3: %E",k,ppw->pv->y[ppw->pv->index_pt_phi_scf], ppw->pvecback[pba->index_bg_phi_prime_scf]); + + // printf("z: %f and k: %f and delta_NEDE: %f and theta_EDE: %f \n",1./a-1,k,ppv->y[ppv->index_pt_delta_NEDE],ppv->y[ppv->index_pt_theta_EDE]); + + ppv->y[ppv->index_pt_shear_NEDE] = sigma_NEDE; + } + /* New EDE */ /*Trigger field evolution stops at transition, no values need to be copied unless the trigger is not sub-dominant.*/ + + if (pba->has_NEDE_trigger_DM == _TRUE_) + { + if (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off) + { + ppv->y[ppv->index_pt_phi_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + + ppv->y[ppv->index_pt_phi_prime_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + } + else if (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on) + { + ppv->y[ppv->index_pt_delta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_delta_trigger_fld]; + + ppv->y[ppv->index_pt_theta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + + if (pba->has_ncdm == _TRUE_) + { + index_pt = 0; + for (n_ncdm = 0; n_ncdm < ppv->N_ncdm; n_ncdm++) + { + for (index_q = 0; index_q < ppv->q_size_ncdm[n_ncdm]; index_q++) + { + for (l = 0; l <= ppv->l_max_ncdm[n_ncdm]; l++) + { + /* This is correct even when ncdmfa == off, since ppv->l_max_ncdm and + ppv->q_size_ncdm is updated.*/ + ppv->y[ppv->index_pt_psi0_ncdm1 + index_pt] = + ppw->pv->y[ppw->pv->index_pt_psi0_ncdm1 + index_pt]; + index_pt++; + } + } + } + } + } + + /*New EDE: Here we stop tracking the evolution of NEDE + perturbations as the NEDE fluid has becomes sufficiently suppressed.*/ + if ((pa_old[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_sda] == (int)sda_on)) + { + + if (ppt->perturbations_verbose > 2) + fprintf(stdout, "Stop tracking EDE mode k=%e at tau=%e\n", k, tau); + + if (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off) + { + + ppv->y[ppv->index_pt_delta_g] = + ppw->pv->y[ppw->pv->index_pt_delta_g]; + + ppv->y[ppv->index_pt_theta_g] = + ppw->pv->y[ppw->pv->index_pt_theta_g]; + } + if ((ppw->approx[ppw->index_ap_tca] == (int)tca_off) && (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off)) + { + + ppv->y[ppv->index_pt_shear_g] = + ppw->pv->y[ppw->pv->index_pt_shear_g]; + + ppv->y[ppv->index_pt_l3_g] = + ppw->pv->y[ppw->pv->index_pt_l3_g]; + + for (l = 4; l <= ppw->pv->l_max_g; l++) + { + + ppv->y[ppv->index_pt_delta_g + l] = + ppw->pv->y[ppw->pv->index_pt_delta_g + l]; + } + + ppv->y[ppv->index_pt_pol0_g] = + ppw->pv->y[ppw->pv->index_pt_pol0_g]; + + ppv->y[ppv->index_pt_pol1_g] = + ppw->pv->y[ppw->pv->index_pt_pol1_g]; + + ppv->y[ppv->index_pt_pol2_g] = + ppw->pv->y[ppw->pv->index_pt_pol2_g]; + + ppv->y[ppv->index_pt_pol3_g] = + ppw->pv->y[ppw->pv->index_pt_pol3_g]; + + for (l = 4; l <= ppw->pv->l_max_pol_g; l++) + { + + ppv->y[ppv->index_pt_pol0_g + l] = + ppw->pv->y[ppw->pv->index_pt_pol0_g + l]; + } + } + + if (pba->has_ur == _TRUE_) + { + + if (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off) + { + + ppv->y[ppv->index_pt_delta_ur] = + ppw->pv->y[ppw->pv->index_pt_delta_ur]; + + ppv->y[ppv->index_pt_theta_ur] = + ppw->pv->y[ppw->pv->index_pt_theta_ur]; + + ppv->y[ppv->index_pt_shear_ur] = + ppw->pv->y[ppw->pv->index_pt_shear_ur]; + + if (ppw->approx[ppw->index_ap_ufa] == (int)ufa_off) + { + + ppv->y[ppv->index_pt_l3_ur] = + ppw->pv->y[ppw->pv->index_pt_l3_ur]; + + for (l = 4; l <= ppv->l_max_ur; l++) + ppv->y[ppv->index_pt_delta_ur + l] = + ppw->pv->y[ppw->pv->index_pt_delta_ur + l]; + } + } + } + + if (pba->has_idr == _TRUE_) + { + + if (ppw->approx[ppw->index_ap_rsa_idr] == (int)rsa_idr_off) + { + + ppv->y[ppv->index_pt_delta_idr] = + ppw->pv->y[ppw->pv->index_pt_delta_idr]; + + ppv->y[ppv->index_pt_theta_idr] = + ppw->pv->y[ppw->pv->index_pt_theta_idr]; + + if (ppt->idr_nature == idr_free_streaming) + { + + if ((ppt->has_idm_dr == _FALSE_) || ((ppt->has_idm_dr == _TRUE_) && (ppw->approx[ppw->index_ap_tca_idm_dr] == (int)tca_idm_dr_off))) + { + + ppv->y[ppv->index_pt_shear_idr] = + ppw->pv->y[ppw->pv->index_pt_shear_idr]; + + ppv->y[ppv->index_pt_l3_idr] = + ppw->pv->y[ppw->pv->index_pt_l3_idr]; + + for (l = 4; l <= ppv->l_max_idr; l++) + ppv->y[ppv->index_pt_delta_idr + l] = + ppw->pv->y[ppw->pv->index_pt_delta_idr + l]; + } + } + } + } + + if (pba->has_ncdm == _TRUE_) + { + index_pt = 0; + for (n_ncdm = 0; n_ncdm < ppv->N_ncdm; n_ncdm++) + { + for (index_q = 0; index_q < ppv->q_size_ncdm[n_ncdm]; index_q++) + { + for (l = 0; l <= ppv->l_max_ncdm[n_ncdm]; l++) + { + /* This is correct even when ncdmfa == off, since ppv->l_max_ncdm and ppv->q_size_ncdm is updated.*/ + ppv->y[ppv->index_pt_psi0_ncdm1 + index_pt] = + ppw->pv->y[ppw->pv->index_pt_psi0_ncdm1 + index_pt]; + index_pt++; + } + } + } + } + + /* We still track the trigger if we are in the trigger DM scenario.*/ + + if (pba->has_NEDE_trigger_DM == _TRUE_) + { + if (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off) + { + ppv->y[ppv->index_pt_phi_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + + ppv->y[ppv->index_pt_phi_prime_trigger] = + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + } + else if (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on) + { + ppv->y[ppv->index_pt_delta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_delta_trigger_fld]; + + ppv->y[ppv->index_pt_theta_trigger_fld] = + ppw->pv->y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + } + + /* -- case of switching on trigger fluid + approximation. Provide correct initial conditions to new set + of variables */ + + if (pba->has_NEDE_trigger_DM == _TRUE_) + { + + if ((pa_old[ppw->index_ap_tfa] == (int)tfa_off) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + + if (ppt->perturbations_verbose > 2) + fprintf(stdout, "Mode k=%e: switch on trigger fluid approximation at tau=%e\n", k, tau); + + if (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off) + { + + ppv->y[ppv->index_pt_delta_g] = + ppw->pv->y[ppw->pv->index_pt_delta_g]; + + ppv->y[ppv->index_pt_theta_g] = + ppw->pv->y[ppw->pv->index_pt_theta_g]; + } + + if ((ppw->approx[ppw->index_ap_tca] == (int)tca_off) && (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off)) + { + + ppv->y[ppv->index_pt_shear_g] = + ppw->pv->y[ppw->pv->index_pt_shear_g]; + + ppv->y[ppv->index_pt_l3_g] = + ppw->pv->y[ppw->pv->index_pt_l3_g]; + + for (l = 4; l <= ppw->pv->l_max_g; l++) + { + + ppv->y[ppv->index_pt_delta_g + l] = + ppw->pv->y[ppw->pv->index_pt_delta_g + l]; + } + + ppv->y[ppv->index_pt_pol0_g] = + ppw->pv->y[ppw->pv->index_pt_pol0_g]; + + ppv->y[ppv->index_pt_pol1_g] = + ppw->pv->y[ppw->pv->index_pt_pol1_g]; + + ppv->y[ppv->index_pt_pol2_g] = + ppw->pv->y[ppw->pv->index_pt_pol2_g]; + + ppv->y[ppv->index_pt_pol3_g] = + ppw->pv->y[ppw->pv->index_pt_pol3_g]; + + for (l = 4; l <= ppw->pv->l_max_pol_g; l++) + { + + ppv->y[ppv->index_pt_pol0_g + l] = + ppw->pv->y[ppw->pv->index_pt_pol0_g + l]; + } + } + + if (pba->has_ur == _TRUE_) + { + + if (ppw->approx[ppw->index_ap_rsa] == (int)rsa_off) + { + + ppv->y[ppv->index_pt_delta_ur] = + ppw->pv->y[ppw->pv->index_pt_delta_ur]; + + ppv->y[ppv->index_pt_theta_ur] = + ppw->pv->y[ppw->pv->index_pt_theta_ur]; + + ppv->y[ppv->index_pt_shear_ur] = + ppw->pv->y[ppw->pv->index_pt_shear_ur]; + + if (ppw->approx[ppw->index_ap_ufa] == (int)ufa_off) + { + + ppv->y[ppv->index_pt_l3_ur] = + ppw->pv->y[ppw->pv->index_pt_l3_ur]; + + for (l = 4; l <= ppv->l_max_ur; l++) + ppv->y[ppv->index_pt_delta_ur + l] = + ppw->pv->y[ppw->pv->index_pt_delta_ur + l]; + } + } + } + + /*New EDE*/ + /*NEDE fluid perturbations not affectecd by trigger fluid approximation, so we just copy the values from the previous integration step.*/ + if (pba->has_NEDE_pert == _TRUE_) + { + + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + ppv->y[ppv->index_pt_delta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_delta_NEDE]; + + ppv->y[ppv->index_pt_theta_NEDE] = + ppw->pv->y[ppw->pv->index_pt_theta_NEDE]; + + ppv->y[ppv->index_pt_shear_NEDE] = + ppw->pv->y[ppw->pv->index_pt_shear_NEDE]; + } + + // New EDE: Here we do the matching for he NEDE trigger field perturbations when the fluid approximation starts. + a = ppw->pvecback[pba->index_bg_a]; + // double a_prime_over_a = ppw->pvecback[pba->index_bg_H] * a; + // double a2 = a * a; + // double k2 = k * k; + + // printf("k: %f, ma: %f , naive delta-rho: %e, average: %e,m cs: %e, x: %e \n", k, pba->NEDE_trigger_mass * a, delta_rho_trigger, ppw->pv->y[ppw->pv->index_pt_delta_trigger_cycle_integral] / ppw->pv->y[ppw->pv->index_pt_theta_hat_t_trigger_cycle_integral], cs2_trigger, ppw->pv->y[ppw->pv->index_pt_phi_trigger]); + + // We use the description proposed in arXiv:2201.10238 //stop2 + + double phi_fluid = ppw->pvecback[pba->index_bg_phi_trigger]; + double phi_prime_fluid = ppw->pvecback[pba->index_bg_phi_prime_trigger]; + + double hL_prime = ppw->pvecmetric[ppw->index_mt_h_prime]; + + double delta_phi_fluid = ppw->pv->y[ppw->pv->index_pt_phi_trigger]; + double delta_phi_prime_fluid = ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger]; + + double H = pba->H_fluid; // ppw->pvecback[pba->index_bg_H]; + double H_prime = pba->H_prime_fluid; // ppw->pvecback[pba->index_bg_H_prime]; + double m = pba->NEDE_trigger_mass; + + // printf("m: %e, H: %e, H_prime %e, hL_prime: %e, a: %e,k: %e, phi_fluid: %e, phi_prime_fluid: %e, delta_phi_fluid: %e, delta_phi_prime_fluid: %e \n",m, H, H_prime,hL_prime,a, k, phi_fluid,phi_prime_fluid,delta_phi_fluid,delta_phi_prime_fluid); + + double fac = 6.0 * pow(H, 2) / (9.0 * pow(H, 4) - 4 * (4 * pow(H, 2) * pow(m, 2) + pow(H_prime, 2) / pow(a, 2))); + + double phi_c_p = fac * (4.0 * H * m * phi_fluid + 3.0 * pow(H, 2) * phi_prime_fluid / a / m + 2.0 * H_prime * phi_prime_fluid / pow(a, 2) / m); + + double phi_s_p = fac * (3.0 * pow(H, 2) * phi_fluid - 2.0 * H_prime / a * phi_fluid + 4.0 * H * phi_prime_fluid / a); + + double phi_c = phi_fluid; + + double phi_s = phi_prime_fluid / a / m - phi_c_p; + + double delta_phi_c_p = H / (-8.0 * pow(H * k, 2) * m + a * a * m * (9 * pow(H, 4) - 4.0 * (4.0 * pow(H * m, 2) + pow(H_prime / a, 2)))) * (2.0 * k * k * (3.0 * H * H * delta_phi_fluid + 2.0 * H_prime / a * delta_phi_fluid - 4.0 * H * delta_phi_prime_fluid / a) + a * a * m * (2.0 * hL_prime / a * H_prime / a * (phi_c_p + phi_s) + 3.0 * H * H * m * (hL_prime / a / m * (phi_c_p + phi_s) + 8.0 * delta_phi_fluid) + 18.0 * pow(H, 3) * delta_phi_prime_fluid / a / m + 4.0 * H * m * (hL_prime / a * (phi_c - phi_s_p) + 3.0 * H_prime / a / m * delta_phi_prime_fluid / a / m))); + + double delta_phi_s_p = -H / pow(a, 2) / m / (-8.0 * pow(H * k, 2) * m + a * a * m * (9.0 * pow(H, 4) - 4.0 * (4.0 * pow(H * m, 2) + pow(H_prime / a, 2)))) * (-4.0 * H * pow(k, 4) * delta_phi_fluid - 2.0 * pow(a * k, 2) * m * (H * m * (hL_prime / a / m * (phi_c_p + phi_s) + 4.0 * delta_phi_fluid) + 3.0 * pow(H, 2) * delta_phi_prime_fluid / a / m + 2.0 * H_prime / a * delta_phi_prime_fluid / a / m) - pow(a * a * m, 2) * (2.0 * hL_prime / a * H_prime / a * (-phi_c + phi_s_p) + 18.0 * pow(H, 3) * delta_phi_fluid + 4.0 * H * m * (hL_prime / a * (phi_c_p + phi_s) - 3.0 * H_prime / a / m * delta_phi_fluid) + 3.0 * H * H * m * (hL_prime / a / m * phi_c - hL_prime / a / m * phi_s_p + 8.0 * delta_phi_prime_fluid / a / m))); + + double delta_phi_c = delta_phi_fluid; + + double delta_phi_s = delta_phi_prime_fluid / a / m - delta_phi_c_p; + + double delta_rho_trigger = 0.5 * m * m * (phi_s * delta_phi_c_p - phi_c * delta_phi_s_p + delta_phi_c_p * phi_c_p + delta_phi_s_p * phi_s_p + delta_phi_s * (2.0 * phi_s + phi_c_p) + delta_phi_c * (2.0 * phi_c - phi_s_p)); + delta_rho_trigger = delta_rho_trigger / 3.0; // CLASS convention! + + double rho_plus_p_theta_trigger_fld = k * k * m / (2.0 * a) * (delta_phi_c * (phi_s + phi_c_p) + delta_phi_s * (-phi_c + phi_s_p)); + rho_plus_p_theta_trigger_fld = rho_plus_p_theta_trigger_fld / 3.0; // CLASS convention! - ppv->y[ppv->index_pt_shear_ur] = - ppw->pv->y[ppw->pv->index_pt_shear_ur]; + double rho_tfa = 0.5 * pow(m, 2) * (phi_c * phi_c + phi_s * phi_s + 0.5 * (phi_c_p * phi_c_p + phi_s_p * phi_s_p) - phi_c * phi_s_p + phi_s * phi_c_p); + rho_tfa = rho_tfa / 3.0; // CLASS convention! - if (ppw->approx[ppw->index_ap_ufa] == (int)ufa_off) { + double p_tfa = 0.5 * pow(m, 2) * (phi_c_p * phi_c_p / 2.0 + phi_s_p * phi_s_p / 2.0 - phi_c * phi_s_p + phi_s * phi_c_p); + p_tfa = p_tfa / 3.0; // CLASS convention! - ppv->y[ppv->index_pt_l3_ur] = - ppw->pv->y[ppw->pv->index_pt_l3_ur]; + // printf("delta_phi_c: %e, delta_phi_s: %e, delta_phi_c_p: %e, delta_phi_s_p: %e, delta_rho_trigger: %e, rho_plus_p_theta_trigger_fld: %e, rho_tfa: %e,p_tfa: %e, phi_c: %e, phi_s: %e, phi_c_p: %e, phi_s_p: %e \n",delta_phi_c,delta_phi_s,delta_phi_c_p,delta_phi_s_p, delta_rho_trigger,rho_plus_p_theta_trigger_fld,rho_tfa,p_tfa,phi_c,phi_s,phi_c_p, phi_s_p); - for (l=4; l <= ppv->l_max_ur; l++) - ppv->y[ppv->index_pt_delta_ur+l] = - ppw->pv->y[ppw->pv->index_pt_delta_ur+l]; + ppv->y[ppv->index_pt_delta_trigger_fld] = delta_rho_trigger / rho_tfa; + ppv->y[ppv->index_pt_theta_trigger_fld] = rho_plus_p_theta_trigger_fld / (rho_tfa + p_tfa); + + // printf("tau: %f, H: %e, a: %e, H_prime: %e ,factor: %e, rho_tfa:%e , p_tfa: %e\n",tau,H,a,H_prime, fac,rho_tfa, p_tfa); + // printf("delta_rho_old: %e, delta_rho_Hu: %e, Theta: %e, Theta Hu: %e \n",ppv->y[ppv->index_pt_delta_trigger_fld]*ppw->pvecback[pba->index_bg_rho_trigger],delta_rho_trigger,ppw->pv->y[ppw->pv->index_pt_theta_hat_trigger_cycle_integral] / (pba->tau_trigger_fluid - pba->tau_trigger_average_start)*ppw->pvecback[pba->index_bg_rho_trigger],rho_plus_p_theta_trigger_fld); + // printf("k: %f, aH: %f, h': %f, eta': %e, alpha1: %f, alpha2: %f \n",k,a_prime_over_a ,ppw->pvecmetric[ppw->index_mt_h_prime],ppw->pvecmetric[ppw->index_mt_eta_prime]/tau,(ppw->pvecmetric[ppw->index_mt_h_prime] + 6.0*ppw->pvecmetric[ppw->index_mt_eta_prime])/(2.0 *k*k),ppw->pvecmetric[ppw->index_mt_alpha]); - } } - } - if (pba->has_idr == _TRUE_){ - if (ppw->approx[ppw->index_ap_rsa_idr] == (int)rsa_idr_off){ + if (pba->has_idr == _TRUE_) + { + if (ppw->approx[ppw->index_ap_rsa_idr] == (int)rsa_idr_off) + { - ppv->y[ppv->index_pt_delta_idr] = - ppw->pv->y[ppw->pv->index_pt_delta_idr]; + ppv->y[ppv->index_pt_delta_idr] = + ppw->pv->y[ppw->pv->index_pt_delta_idr]; - ppv->y[ppv->index_pt_theta_idr] = - ppw->pv->y[ppw->pv->index_pt_theta_idr]; + ppv->y[ppv->index_pt_theta_idr] = + ppw->pv->y[ppw->pv->index_pt_theta_idr]; - if (ppt->idr_nature == idr_free_streaming){ + if (ppt->idr_nature == idr_free_streaming) + { - if (ppw->approx[ppw->index_ap_tca_idm_dr] == (int)tca_idm_dr_off){ + if ((ppt->has_idm_dr == _FALSE_) || ((ppt->has_idm_dr == _TRUE_) && (ppw->approx[ppw->index_ap_tca_idm_dr] == (int)tca_idm_dr_off))) + { - ppv->y[ppv->index_pt_shear_idr] = - ppw->pv->y[ppw->pv->index_pt_shear_idr]; + ppv->y[ppv->index_pt_shear_idr] = + ppw->pv->y[ppw->pv->index_pt_shear_idr]; - ppv->y[ppv->index_pt_l3_idr] = - ppw->pv->y[ppw->pv->index_pt_l3_idr]; + ppv->y[ppv->index_pt_l3_idr] = + ppw->pv->y[ppw->pv->index_pt_l3_idr]; - for (l=4; l <= ppv->l_max_idr; l++) - ppv->y[ppv->index_pt_delta_idr+l] = - ppw->pv->y[ppw->pv->index_pt_delta_idr+l]; + for (l = 4; l <= ppv->l_max_idr; l++) + ppv->y[ppv->index_pt_delta_idr + l] = + ppw->pv->y[ppw->pv->index_pt_delta_idr + l]; + } } } } - } - - - a = ppw->pvecback[pba->index_bg_a]; - index_pt = ppw->pv->index_pt_psi0_ncdm1; - for (n_ncdm = 0; n_ncdm < ppv->N_ncdm; n_ncdm++){ - // We are in the fluid approximation, so ncdm_l_size is always 3. - ncdm_l_size = ppv->l_max_ncdm[n_ncdm]+1; - rho_plus_p_ncdm = ppw->pvecback[pba->index_bg_rho_ncdm1+n_ncdm]+ - ppw->pvecback[pba->index_bg_p_ncdm1+n_ncdm]; - for (l=0; l<=2; l++){ - ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+l] = 0.0; - } - factor = pba->factor_ncdm[n_ncdm]/pow(a,4); - for (index_q=0; index_q < ppw->pv->q_size_ncdm[n_ncdm]; index_q++){ - // Integrate over distributions: - q = pba->q_ncdm[n_ncdm][index_q]; - q2 = q*q; - epsilon = sqrt(q2+a*a*pba->M_ncdm[n_ncdm]*pba->M_ncdm[n_ncdm]); - ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm] += - pba->w_ncdm[n_ncdm][index_q]*q2*epsilon* - ppw->pv->y[index_pt]; - - ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+1] += - pba->w_ncdm[n_ncdm][index_q]*q2*q* - ppw->pv->y[index_pt+1]; - - ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+2] += - pba->w_ncdm[n_ncdm][index_q]*q2*q2/epsilon* - ppw->pv->y[index_pt+2]; - //Jump to next momentum bin in ppw->pv->y: - index_pt += (ppw->pv->l_max_ncdm[n_ncdm]+1); + if (pba->has_ncdm == _TRUE_) + { + index_pt = 0; + for (n_ncdm = 0; n_ncdm < ppv->N_ncdm; n_ncdm++) + { + for (index_q = 0; index_q < ppv->q_size_ncdm[n_ncdm]; index_q++) + { + for (l = 0; l <= ppv->l_max_ncdm[n_ncdm]; l++) + { + /* This is correct even when ncdmfa == off, since ppv->l_max_ncdm and + ppv->q_size_ncdm is updated.*/ + ppv->y[ppv->index_pt_psi0_ncdm1 + index_pt] = + ppw->pv->y[ppw->pv->index_pt_psi0_ncdm1 + index_pt]; + index_pt++; + } + } + } } - ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm] *=factor/ppw->pvecback[pba->index_bg_rho_ncdm1+n_ncdm]; - ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+1] *=k*factor/rho_plus_p_ncdm; - ppv->y[ppv->index_pt_psi0_ncdm1+ncdm_l_size*n_ncdm+2] *=2.0/3.0*factor/rho_plus_p_ncdm; } } } @@ -5575,6 +6494,22 @@ int perturbations_initial_conditions(struct precision * ppr, /* delta_fld expression * rho_scf with the w = 1/3, c_s = 1 a*a/ppw->pvecback[pba->index_bg_phi_prime_scf]*( - ktau_two/4.*(1.+1./3.)*(4.-3.*1.)/(4.-6.*(1/3.)+3.*1.)*ppw->pvecback[pba->index_bg_rho_scf] - ppw->pvecback[pba->index_bg_dV_scf]*ppw->pv->y[ppw->pv->index_pt_phi_scf])* ppr->curvature_ini * s2_squared; */ } + + /*New EDE: Here we set adiabatic intial conditions for the trigger field.*/ + if ((pba->has_NEDE_pert == _TRUE_) && (pba->has_NEDE_trigger == _TRUE_)) + { + if (ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) + { + + ppw->pv->y[ppw->pv->index_pt_phi_trigger] = -1. / 140. * pba->phi_ini_trigger * ppw->pv->y[ppw->pv->index_pt_delta_g] * pow(pba->NEDE_trigger_mass / ppw->pvecback[pba->index_bg_H], 2); + + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger] = -3. / 70. * pba->phi_ini_trigger * ppw->pv->y[ppw->pv->index_pt_delta_g] * pow(pba->NEDE_trigger_mass, 2) * a / ppw->pvecback[pba->index_bg_H]; + } + else + { + class_test(0 == 0, ppt->error_message, "NEDE Cosmological approximation was not 'on' at initial time.\n"); + } + } /* all relativistic relics: ur, early ncdm, dr */ @@ -5848,6 +6783,34 @@ int perturbations_initial_conditions(struct precision * ppr, -a*a* dV_scf(pba,ppw->pvecback[pba->index_bg_phi_scf])*alpha +ppw->pvecback[pba->index_bg_phi_prime_scf]*alpha_prime); } + + /*New EDE: Convert inital conditions to Newtonian gauge / danger: we never have tested this part as we only use synchronous gauge*/ + if (pba->has_NEDE_pert == _TRUE_) + { + + /* New EDE: trigger field like scf above */ + if ((pba->has_NEDE_trigger == _TRUE_) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_on)) + { + alpha_prime = 0.0; + + ppw->pv->y[ppw->pv->index_pt_phi_trigger] += alpha * ppw->pvecback[pba->index_bg_phi_prime_trigger]; + ppw->pv->y[ppw->pv->index_pt_phi_prime_trigger] += + (-2. * a_prime_over_a * alpha * ppw->pvecback[pba->index_bg_phi_prime_trigger] - a * a * dV_trigger(pba, ppw->pvecback[pba->index_bg_phi_trigger]) * alpha + ppw->pvecback[pba->index_bg_phi_prime_trigger] * alpha_prime); + } + + if (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off) // This part is not relevant as NEDE is initialized at later times, we still included it for self-consistency. + { + double w_NEDE; + class_call(background_quantities_NEDE(pba, a, a_prime_over_a, NULL, NULL, &w_NEDE, NULL, NULL), + pba->error_message, + pba->error_message); + + ppw->pv->y[ppw->pv->index_pt_delta_NEDE] -= 3 * (1. + w_NEDE) * a_prime_over_a * alpha; + ppw->pv->y[ppw->pv->index_pt_theta_NEDE] += k * k * alpha; + } + } + + if ((pba->has_ur == _TRUE_) || (pba->has_ncdm == _TRUE_) || (pba->has_dr == _TRUE_) || (pba->has_idr == _TRUE_)) { @@ -6263,6 +7226,47 @@ int perturbations_approximations( else { ppw->approx[ppw->index_ap_rsa] = (int)rsa_off; } + + + /*New EDE*/ + /*define NEDE phases*/ + if (pba->has_NEDE_pert == _TRUE_) + { + /*before transition CCa_on*/ + if (1. / ppw->pvecback[pba->index_bg_a] - 1. > pba->z_decay_NEDE) + { + ppw->approx[ppw->index_ap_CCa] = (int)CCa_on; + } + /*after transition CCa_off*/ + else + { + ppw->approx[ppw->index_ap_CCa] = (int)CCa_off; + } + /*When the NEDE fluid becomes highly subdominant set sda_on*/ + if ((1. / ppw->pvecback[pba->index_bg_a] - 1. < pba->z_decay_NEDE * 0.9) && (ppw->pvecback[pba->index_bg_rho_NEDE] / pow(ppw->pvecback[pba->index_bg_H], 2) < ppr->sub_dom_cond)) + { + ppw->approx[ppw->index_ap_sda] = (int)sda_on; + } + else + { + ppw->approx[ppw->index_ap_sda] = (int)sda_off; + } + + /*New EDE: Here we define the switch for the trigger fluid approximation*/ // stop3 + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->pvecback[pba->index_bg_a] <= pba->a_trigger_fluid) || (pba->has_NEDE_trigger_DM == _FALSE_)) + { + ppw->approx[ppw->index_ap_tfa] = (int)tfa_off; + } + else + { + ppw->approx[ppw->index_ap_tfa] = (int)tfa_on; + } + } + } + + /* interacting dark radiation free streaming approximation*/ if (pba->has_idr == _TRUE_){ @@ -6820,6 +7824,11 @@ int perturbations_total_stress_energy( double X, Y, Z, X_prime, Y_prime, Z_prime; double Gamma_fld, S, S_prime, theta_t, theta_t_prime, rho_plus_p_theta_fld_prime; double delta_p_b_over_rho_b; + double delta_NEDE = 0.; + double theta_NEDE = 0.; + double shear_NEDE = 0.; + double delta_trigger = 0.; + double theta_trigger = 0.; /** - wavenumber and scale factor related quantities */ @@ -7151,6 +8160,161 @@ int perturbations_total_stress_energy( } } } + + /*New EDE*/ + /*Here contributions to EMT are collected*/ + if (pba->has_NEDE_pert == _TRUE_) + { + + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + + delta_NEDE = y[ppw->pv->index_pt_delta_NEDE]; + theta_NEDE = y[ppw->pv->index_pt_theta_NEDE]; + shear_NEDE = y[ppw->pv->index_pt_shear_NEDE]; + } + else + { + delta_NEDE = 0.; + theta_NEDE = 0.; + shear_NEDE = 0.; + } + + if (pba->has_NEDE_trigger_DM == _TRUE_) + { + if (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on) + { + delta_trigger = y[ppw->pv->index_pt_delta_trigger_fld]; + theta_trigger = y[ppw->pv->index_pt_theta_trigger_fld]; + } + } + + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_off) && (ppw->approx[ppw->index_ap_sda] == (int)sda_off)) + { + double w_NEDE, dw_over_da_NEDE, ca2_NEDE, cs2_NEDE; + class_call(background_quantities_NEDE(pba, a, a_prime_over_a, NULL, NULL, &w_NEDE, &dw_over_da_NEDE, &ca2_NEDE), + pba->error_message, + pba->error_message); + /** Decide if effective rest-frame sound speed is constant or tracking the adiabatic sound speed (note that w_NEDE=const). */ + + if (pba->NEDE_fld_nature == NEDE_fld_A) + { + if (ppt->NEDE_ceff_nature == NEDE_ceff_const) + cs2_NEDE = ppt->three_ceff2_NEDE / 3.; + else if (ppt->NEDE_ceff_nature == NEDE_ceff_tracking) + cs2_NEDE = ca2_NEDE; + else if (ppt->NEDE_ceff_nature == NEDE_ceff_twice_linear) { + double k_horizon = 2*_PI_*a*ppw->pvecback[pba->index_bg_H]; + if (k > k_horizon) { + cs2_NEDE = ppt->NEDE_cs2_slope_1*k + ppt->NEDE_cs2_intercept_1; + } + else { + cs2_NEDE = ppt->NEDE_cs2_slope_2*k + ppt->NEDE_cs2_intercept_2; + } + class_test(cs2_NEDE < 0., ppt->error_message, "NEDE sound speed is negative with the given 'twice linear' parametrisation parameters.") + } + else { + class_stop(ppt->error_message, "NEDE c_eff nature not understood.") + } + } + else { + class_stop(ppt->error_message, "NEDE fld nature not understood.") + } + + ppw->delta_rho = ppw->delta_rho + ppw->pvecback[pba->index_bg_rho_NEDE] * delta_NEDE; + + ppw->rho_plus_p_theta = ppw->rho_plus_p_theta + (1. + w_NEDE) * ppw->pvecback[pba->index_bg_rho_NEDE] * theta_NEDE; + + ppw->rho_plus_p_shear = ppw->rho_plus_p_shear + (1. + w_NEDE) * ppw->pvecback[pba->index_bg_rho_NEDE] * shear_NEDE; + + /*Compare to arXiv: astro-ph/9801234v2, Eq. 3 and thereafter; use dictionnary theta/k = v.*/ + ppw->delta_p += cs2_NEDE * ppw->pvecback[pba->index_bg_rho_NEDE] * delta_NEDE + (cs2_NEDE - ca2_NEDE) * (3. * a_prime_over_a * ((1. + w_NEDE) * ppw->pvecback[pba->index_bg_rho_NEDE] * theta_NEDE) / k / k); + + /* This part is implemented overly correct as first case cannot happen*/ + if (a < pba->a_decay) + { + ppw->rho_plus_p_tot += 0.0; + } + else + { + ppw->rho_plus_p_tot += (1. + w_NEDE) * ppw->pvecback[pba->index_bg_rho_NEDE]; + } + } + } + + /*Trigger contribution / like scalar field below*/ + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + // This is the case when the scalar field is tracked. + double delta_rho_trigger, delta_p_trigger; + if (ppt->gauge == synchronous) + { + + delta_rho_trigger = 1. / 3. * + (1. / a2 * ppw->pvecback[pba->index_bg_phi_prime_trigger] * y[ppw->pv->index_pt_phi_prime_trigger] + ppw->pvecback[pba->index_bg_dV_trigger] * y[ppw->pv->index_pt_phi_trigger]); + delta_p_trigger = 1. / 3. * + (1. / a2 * ppw->pvecback[pba->index_bg_phi_prime_trigger] * y[ppw->pv->index_pt_phi_prime_trigger] - ppw->pvecback[pba->index_bg_dV_trigger] * y[ppw->pv->index_pt_phi_trigger]); + } + else + { + /* equation for psi */ + psi = y[ppw->pv->index_pt_phi] - 4.5 * (a2 / k / k) * ppw->rho_plus_p_shear; + + delta_rho_trigger = 1. / 3. * + (1. / a2 * ppw->pvecback[pba->index_bg_phi_prime_trigger] * y[ppw->pv->index_pt_phi_prime_trigger] + ppw->pvecback[pba->index_bg_dV_trigger] * y[ppw->pv->index_pt_phi_trigger] - 1. / a2 * pow(ppw->pvecback[pba->index_bg_phi_prime_trigger], 2) * psi); + delta_p_trigger = 1. / 3. * + (1. / a2 * ppw->pvecback[pba->index_bg_phi_prime_trigger] * y[ppw->pv->index_pt_phi_prime_trigger] - ppw->pvecback[pba->index_bg_dV_trigger] * y[ppw->pv->index_pt_phi_trigger] - 1. / a2 * pow(ppw->pvecback[pba->index_bg_phi_prime_trigger], 2) * psi); + } + + ppw->delta_rho += delta_rho_trigger; + + ppw->rho_plus_p_theta += 1. / 3. * + k * k / a2 * ppw->pvecback[pba->index_bg_phi_prime_trigger] * y[ppw->pv->index_pt_phi_trigger]; + + ppw->delta_p += delta_p_trigger; + + ppw->rho_plus_p_tot += ppw->pvecback[pba->index_bg_rho_trigger] + ppw->pvecback[pba->index_bg_p_trigger]; + } + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + // This is the case when the fluid approximation is used.. + double cs2_trigger = 0; + double ca2_trigger = 0; + double w_trigger = 0; + class_call(trigger_NEDE_cs2(pba, a, k, ppw->pvecback[pba->index_bg_H], &cs2_trigger), + pba->error_message, + pba->error_message); + + class_call(background_quantities_NEDE_trigger(pba, a, a_prime_over_a, ppw->pvecback[pba->index_bg_H], ppw->pvecback[pba->index_bg_H_prime], &w_trigger, NULL, &ca2_trigger), + pba->error_message, + pba->error_message); + + delta_trigger = y[ppw->pv->index_pt_delta_trigger_fld]; + theta_trigger = y[ppw->pv->index_pt_theta_trigger_fld]; + + ppw->delta_rho += ppw->pvecback[pba->index_bg_rho_trigger] * delta_trigger; + + ppw->rho_plus_p_theta = ppw->rho_plus_p_theta + (1. + w_trigger) * ppw->pvecback[pba->index_bg_rho_trigger] * theta_trigger; + + /*Compare to arXiv: astro-ph/9801234v2, Eq. 3 and thereafter; use dictionnary theta/k = v.*/ + ppw->delta_p += cs2_trigger * ppw->pvecback[pba->index_bg_rho_trigger] * delta_trigger + (cs2_trigger - ca2_trigger) * (3. * a_prime_over_a * ((1. + w_trigger) * ppw->pvecback[pba->index_bg_rho_trigger] * theta_trigger) / k / k); + + ppw->rho_plus_p_tot += (1. + w_trigger) * ppw->pvecback[pba->index_bg_rho_trigger]; + + if (ppt->has_source_delta_m == _TRUE_) + { + delta_rho_m += ppw->pvecback[pba->index_bg_rho_trigger] * delta_trigger; // contribution to delta rho_matter + rho_m += ppw->pvecback[pba->index_bg_rho_trigger]; + } + if ((ppt->has_source_delta_m == _TRUE_) || (ppt->has_source_theta_m == _TRUE_)) + { + rho_plus_p_theta_m += (1. + w_trigger) * ppw->pvecback[pba->index_bg_rho_trigger] * theta_trigger; // contribution to [(rho+p)theta]_matter + rho_plus_p_m += (1. + w_trigger) * ppw->pvecback[pba->index_bg_rho_trigger]; + } + } + } /* scalar field contribution. In Newtonian gauge, delta_scf depends on the metric perturbation psi which is inferred @@ -8160,6 +9324,11 @@ int perturbations_print_variables(double tau, double a,a2,H; int idx,index_q, storeidx; double *dataptr; + + /*variables for New EDE*/ + double delta_NEDE = 0., theta_NEDE = 0., shear_NEDE = 0.; + double delta_rho_trigger = 0., rho_plus_p_theta_trigger = 0., cs2_trigger = 0.; + double delta_trigger = 0., theta_trigger = 0.; /** - rename structure fields (just to avoid heavy notations) */ @@ -8280,6 +9449,61 @@ int perturbations_print_variables(double tau, shear_ur = 0.; } } + + /*New EDE*/ + /* Here we infer the perturbations for different approximations in order to print them in a file*/ + if (pba->has_NEDE_pert == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + delta_NEDE = y[ppw->pv->index_pt_delta_NEDE]; + theta_NEDE = y[ppw->pv->index_pt_theta_NEDE]; + shear_NEDE = y[ppw->pv->index_pt_shear_NEDE]; + } + else + { + delta_NEDE = 0.; + theta_NEDE = 0.; + shear_NEDE = 0.; + } + if (pba->has_NEDE_trigger == _TRUE_) + { + + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + if (ppt->gauge == synchronous) + { + delta_rho_trigger = 1. / 3. * + (1. / a2 * ppw->pvecback[pba->index_bg_phi_prime_trigger] * y[ppw->pv->index_pt_phi_prime_trigger] + ppw->pvecback[pba->index_bg_dV_trigger] * y[ppw->pv->index_pt_phi_trigger]); + } + else + { + delta_rho_trigger = 1. / 3. * + (1. / a2 * ppw->pvecback[pba->index_bg_phi_prime_trigger] * y[ppw->pv->index_pt_phi_prime_trigger] + ppw->pvecback[pba->index_bg_dV_trigger] * y[ppw->pv->index_pt_phi_trigger] - 1. / a2 * pow(ppw->pvecback[pba->index_bg_phi_prime_trigger], 2) * ppw->pvecmetric[ppw->index_mt_psi]); + } + + rho_plus_p_theta_trigger = 1. / 3. * + k * k / a2 * ppw->pvecback[pba->index_bg_phi_prime_trigger] * y[ppw->pv->index_pt_phi_trigger]; + + delta_trigger = delta_rho_trigger / pvecback[pba->index_bg_rho_trigger]; + // theta_trigger = rho_plus_p_theta_trigger / (pvecback[pba->index_bg_rho_trigger] + pvecback[pba->index_bg_p_trigger]); + // printf("theta: %e ", theta_trigger); + } + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + + { + + class_call(trigger_NEDE_cs2(pba, a, k, ppw->pvecback[pba->index_bg_H], &cs2_trigger), + pba->error_message, + pba->error_message); + + delta_trigger = y[ppw->pv->index_pt_delta_trigger_fld]; + theta_trigger = y[ppw->pv->index_pt_theta_trigger_fld]; + rho_plus_p_theta_trigger = theta_trigger * (pvecback[pba->index_bg_rho_trigger] + pvecback[pba->index_bg_p_trigger]); + } + } + } + delta_b = y[ppw->pv->index_pt_delta_b]; theta_b = y[ppw->pv->index_pt_theta_b]; @@ -8435,59 +9659,73 @@ int perturbations_print_variables(double tau, } - /* converting synchronous variables to newtonian ones */ + if (ppt->gauge == synchronous) { + if (ppt->plot_gauge == 0) { + /* converting synchronous variables to newtonian ones */ + + /* density and velocity perturbations (comment out if you wish to keep synchronous variables) */ - /* density and velocity perturbations (comment out if you wish to keep synchronous variables) */ - - delta_g -= 4. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; - theta_g += k*k*alpha; + delta_g -= 4. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; + theta_g += k*k*alpha; - delta_b -= 3. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; - theta_b += k*k*alpha; - - if (pba->has_ur == _TRUE_) { - delta_ur -= 4. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; - theta_ur += k*k*alpha; - } + delta_b -= 3. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; + theta_b += k*k*alpha; - if (pba->has_idr == _TRUE_) { - delta_idr -= 4. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; - theta_idr += k*k*alpha; - } + if (pba->has_ur == _TRUE_) { + delta_ur -= 4. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; + theta_ur += k*k*alpha; + } + + /*New EDE*/ + /* We normally have this commented out and plot everything in synchronous gauge*/ + /*Here we convert to Newtonian gauge, not really important for running of code but for plotting / Note that the conversion is only well-defined if the equation of state is not -1*/ + if (pba->has_NEDE_pert) { + delta_NEDE -= 4. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; + theta_NEDE += k*k*alpha; + if (pba->has_NEDE_trigger == _TRUE_){ + delta_trigger += alpha*(-3.0*H*(1.0+pvecback[pba->index_bg_p_trigger]/pvecback[pba->index_bg_rho_trigger])); + theta_trigger += k*k*alpha; + } + } + + if (pba->has_idr == _TRUE_) { + delta_idr -= 4. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; + theta_idr += k*k*alpha; + } - if (pba->has_dr == _TRUE_) { - delta_dr += (-4.*a*H+a*pba->Gamma_dcdm*pvecback[pba->index_bg_rho_dcdm]/pvecback[pba->index_bg_rho_dr])*alpha; + if (pba->has_dr == _TRUE_) { + delta_dr += (-4.*a*H+a*pba->Gamma_dcdm*pvecback[pba->index_bg_rho_dcdm]/pvecback[pba->index_bg_rho_dr])*alpha; - theta_dr += k*k*alpha; - } + theta_dr += k*k*alpha; + } - if (pba->has_cdm == _TRUE_) { - delta_cdm -= 3. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; - theta_cdm += k*k*alpha; - } + if (pba->has_cdm == _TRUE_) { + delta_cdm -= 3. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; + theta_cdm += k*k*alpha; + } - if (pba->has_idm == _TRUE_) { - delta_idm -= 3. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; - theta_idm += k*k*alpha; - } + if (pba->has_idm == _TRUE_) { + delta_idm -= 3. * pvecback[pba->index_bg_H]*pvecback[pba->index_bg_a]*alpha; + theta_idm += k*k*alpha; + } - if (pba->has_ncdm == _TRUE_) { - for (n_ncdm=0; n_ncdm < pba->N_ncdm; n_ncdm++){ - /** - --> TODO: gauge transformation of delta, deltaP/rho (?) and theta using -= 3aH(1+w_ncdm) alpha for delta. */ + if (pba->has_ncdm == _TRUE_) { + for (n_ncdm=0; n_ncdm < pba->N_ncdm; n_ncdm++){ + /** - --> TODO: gauge transformation of delta, deltaP/rho (?) and theta using -= 3aH(1+w_ncdm) alpha for delta. */ + } } - } - if (pba->has_dcdm == _TRUE_) { - delta_dcdm += alpha*(-a*pba->Gamma_dcdm-3.*a*H); - theta_dcdm += k*k*alpha; - } + if (pba->has_dcdm == _TRUE_) { + delta_dcdm += alpha*(-a*pba->Gamma_dcdm-3.*a*H); + theta_dcdm += k*k*alpha; + } - if (pba->has_scf == _TRUE_) { - delta_scf += alpha*(-3.0*H*(1.0+pvecback[pba->index_bg_p_scf]/pvecback[pba->index_bg_rho_scf])); - theta_scf += k*k*alpha; + if (pba->has_scf == _TRUE_) { + delta_scf += alpha*(-3.0*H*(1.0+pvecback[pba->index_bg_p_scf]/pvecback[pba->index_bg_rho_scf])); + theta_scf += k*k*alpha; + } } - } // fprintf(ppw->perturbations_output_file," "); @@ -8561,6 +9799,14 @@ int perturbations_print_variables(double tau, class_store_double(dataptr, ppw->delta_rho_fld, pba->has_fld, storeidx); class_store_double(dataptr, ppw->rho_plus_p_theta_fld, pba->has_fld, storeidx); class_store_double(dataptr, ppw->delta_p_fld, pba->has_fld, storeidx); + /** New EDE*/ + class_store_double(dataptr, delta_NEDE, pba->has_NEDE_pert, storeidx); + class_store_double(dataptr, theta_NEDE, pba->has_NEDE_pert, storeidx); + class_store_double(dataptr, shear_NEDE, pba->has_NEDE_pert, storeidx); + /*New EDE; Trigger field*/ + class_store_double(dataptr, delta_trigger, pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, rho_plus_p_theta_trigger, pba->has_NEDE_trigger, storeidx); + class_store_double(dataptr, cs2_trigger, pba->has_NEDE_trigger, storeidx); //fprintf(ppw->perturbations_output_file,"\n"); } @@ -9621,6 +10867,105 @@ int perturbations_derivs(double tau, } } } + + + /* New EDE */ // stop1 + /*These are the actual perturbation equations. See for example arXiv: 1806.10.608v1 and also Hu in the presence of shear, arXiv: astro-ph/9801234v2*/ + + if (pba->has_NEDE_pert == _TRUE_) + { + + if ((ppw->approx[ppw->index_ap_sda] == (int)sda_off) && (ppw->approx[ppw->index_ap_CCa] == (int)CCa_off)) + { + double w_NEDE, dw_over_da_NEDE, ca2_NEDE, cs2_NEDE; + class_call(background_quantities_NEDE(pba, a, a_prime_over_a, NULL, NULL, &w_NEDE, &dw_over_da_NEDE, &ca2_NEDE), + pba->error_message, + pba->error_message); + + /*The NEDE implementation so far assumes w_prime_NEDE=0*/ + + /** Decide if effective rest-frame sound speed is constant or tracking the adiabatic sound speed (note that w_NEDE=const). */ + + if (pba->NEDE_fld_nature == NEDE_fld_A) + { + if (ppt->NEDE_ceff_nature == NEDE_ceff_const) + cs2_NEDE = ppt->three_ceff2_NEDE / 3.; + else if (ppt->NEDE_ceff_nature == NEDE_ceff_tracking) + cs2_NEDE = ca2_NEDE; + else if (ppt->NEDE_ceff_nature == NEDE_ceff_twice_linear) { + double k_horizon = 2*_PI_*a*pvecback[pba->index_bg_H]; + if (k > k_horizon) { + cs2_NEDE = ppt->NEDE_cs2_slope_1*k + ppt->NEDE_cs2_intercept_1; + } + else { + cs2_NEDE = ppt->NEDE_cs2_slope_2*k + ppt->NEDE_cs2_intercept_2; + } + } + else { + class_stop(ppt->error_message, "NEDE sound speed not understood.") + } + } + else { + class_stop(ppt->error_message, "NEDE fld nature not understood.") + } + + /** - -----> NEDE density */ + dy[pv->index_pt_delta_NEDE] = + -(1. + w_NEDE) * (y[pv->index_pt_theta_NEDE] + metric_continuity) - 3. * (cs2_NEDE - w_NEDE) * a_prime_over_a * y[pv->index_pt_delta_NEDE] - 9. * (1 + w_NEDE) * (cs2_NEDE - ca2_NEDE) * a_prime_over_a * a_prime_over_a * y[pv->index_pt_theta_NEDE] / k2; + // metric_continuity = h'/2 + + /** - -----> NEDE velocity */ + dy[pv->index_pt_theta_NEDE] = + k2 * (3. * cs2_NEDE * y[pv->index_pt_delta_NEDE] / (3. + 3. * w_NEDE) - s2_squared * y[pv->index_pt_shear_NEDE]) + metric_euler - (1. - 3. * cs2_NEDE) * a_prime_over_a * y[pv->index_pt_theta_NEDE]; + // metric_euler=0 in synchronous gauge and s2_squared = 1 without spatial curvature. //Shear term vanishes in standard NEDE scenario. + + /* Shear, only relevant for cvis2 non-vanishing, in other cases sigma_NEDE=0 all the time. */ + dy[pv->index_pt_shear_NEDE] = + -3. * a_prime_over_a * y[pv->index_pt_shear_NEDE] + 8. / 3. * ppt->three_cvis2_NEDE / (3. * w_NEDE + 3.) * (y[pv->index_pt_theta_NEDE] + metric_shear); + // metric_shear = (h_prime+6eta_prime)/2 in synchronous gauge + } + + /** - ---> trigger field */ + + if (pba->has_NEDE_trigger == _TRUE_) + { + if ((ppw->approx[ppw->index_ap_CCa] == (int)CCa_on) || ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_off))) + { + /** - ----> field value */ + + dy[pv->index_pt_phi_trigger] = y[pv->index_pt_phi_prime_trigger]; + + /** - ----> Klein Gordon equation */ + + dy[pv->index_pt_phi_prime_trigger] = -2. * a_prime_over_a * y[pv->index_pt_phi_prime_trigger] - metric_continuity * pvecback[pba->index_bg_phi_prime_trigger] // metric_continuity = h'/2 + - (k2 + a2 * pvecback[pba->index_bg_ddV_trigger]) * y[pv->index_pt_phi_trigger]; + } + + else if ((pba->has_NEDE_trigger_DM == _TRUE_) && (ppw->approx[ppw->index_ap_tfa] == (int)tfa_on)) + { + double cs2_trigger = 0; + double w_trigger = 0; + double ca2_trigger = 0; + // Get the sound speed. + class_call(trigger_NEDE_cs2(pba, a, k, ppw->pvecback[pba->index_bg_H], &cs2_trigger), + pba->error_message, + pba->error_message); + + // Get other background quantities. + class_call(background_quantities_NEDE_trigger(pba, a, a_prime_over_a, ppw->pvecback[pba->index_bg_H], ppw->pvecback[pba->index_bg_H_prime], &w_trigger, NULL, &ca2_trigger), + pba->error_message, + pba->error_message); + + // These are the standard equations for generic fluid perturbations. + + dy[pv->index_pt_delta_trigger_fld] = -(1. + w_trigger) * (y[pv->index_pt_theta_trigger_fld] + metric_continuity) - 3. * (cs2_trigger - w_trigger) * a_prime_over_a * y[pv->index_pt_delta_trigger_fld] - 9. * (1 + w_trigger) * (cs2_trigger - ca2_trigger) * a_prime_over_a * a_prime_over_a * y[pv->index_pt_theta_trigger_fld] / k2; + + dy[pv->index_pt_theta_trigger_fld] = + k2 * (3. * cs2_trigger * y[pv->index_pt_delta_trigger_fld] / (3. + 3. * w_trigger)) + metric_euler - (1. - 3. * cs2_trigger) * a_prime_over_a * y[pv->index_pt_theta_trigger_fld]; + } + } + } + /** - ---> metric */ @@ -10524,3 +11869,22 @@ int perturbations_rsa_idr_delta_and_theta( return _SUCCESS_; } + +int trigger_NEDE_cs2( + struct background *pba, + double a, + double k, + double H, + double *cs2) +{ + double m; + + m = pba->NEDE_trigger_mass; + + // We use the improved formula for the sound speed derived in arXiv: 2201.10238 + *cs2 = pow((a * m) / k * (pow(1.0 + pow(k / (a * m), 2), 0.5) - 1.0), 2) + 5.0 / 4.0 * pow(H / m, 2); + //*cs2 = k * k / (4.0 * pow(pba->NEDE_trigger_mass, 2) * a * a + k*k); + + return _SUCCESS_; +} + diff --git a/tools/evolver_ndf15.c b/tools/evolver_ndf15.c index 0d2937235..5f8ec3169 100644 --- a/tools/evolver_ndf15.c +++ b/tools/evolver_ndf15.c @@ -549,11 +549,14 @@ int evolver_ndf15( } } /** Output **/ + int output_return; while ((next= 0.0)){ /* Do we need to write output? */ if (tnew==t_vec[next]){ - class_call((*output)(t_vec[next],ynew+1,f0+1,next,parameters_and_workspace_for_derivs,error_message), - error_message,error_message); + + output_return = output(t_vec[next],ynew+1,f0+1,next,parameters_and_workspace_for_derivs,error_message); + // class_call((*output)(t_vec[next],ynew+1,f0+1,next,parameters_and_workspace_for_derivs,error_message), + // error_message,error_message); // MODIFICATION BY LUC // All print_variables have been moved to the end of time step /* @@ -567,11 +570,22 @@ int evolver_ndf15( else { /*Interpolate if we have overshot sample values*/ interp_from_dif(t_vec[next],tnew,ynew,h,dif,k,yinterp,ypinterp,yppinterp,interpidx,neq,2); - - class_call((*output)(t_vec[next],yinterp+1,ypinterp+1,next,parameters_and_workspace_for_derivs, - error_message),error_message,error_message); - + + output_return = output(t_vec[next],yinterp+1,ypinterp+1,next,parameters_and_workspace_for_derivs,error_message); + // class_call((*output)(t_vec[next],yinterp+1,ypinterp+1,next,parameters_and_workspace_for_derivs, + // error_message),error_message,error_message); + } + + if (output_return == _FAILURE_) { + // Cast CLASS error message by mimicing the class_call macro + class_call_message(error_message, output, error_message) + return _FAILURE_; } + else if (output_return == _APPROXIMATION_REACHED_) { + // Early stopping due to turning on approximation + done = _TRUE_; + } + next++; } /** End of output **/ @@ -1084,7 +1098,7 @@ int fzero_Newton(int (*func)(double *x, take ntrial Newton-Raphson steps to improve the root. Stop if the root converges in either summed absolute variable increments tolx or summed absolute function values tolf.*/ - int k,i,j,*indx, ntrial=20; + int k,i,j,*indx, ntrial=30; double errx,errf,d,*F0,*Fdel,**Fjac,*p, *lu_work; int has_converged = _FALSE_; int funcreturn; @@ -1115,6 +1129,13 @@ int fzero_Newton(int (*func)(double *x, /** Compute F(x): */ /**printf("x = [%f, %f], delx = [%e, %e]\n", x_inout[0],x_inout[1],delx[0],delx[1]);*/ + /* + printf("Evaluating at x_inout: "); + for (int asdf = 0; asdf < x_size; asdf++) { + printf("x[%d]=%g, ", asdf, x_inout[asdf]); + } + printf("\n"); + */ class_call(func(x_inout, x_size, param, F0, error_message), error_message, error_message); /** printf("F0 = [%f, %f]\n",F0[0],F0[1]);*/ @@ -1127,31 +1148,75 @@ int fzero_Newton(int (*func)(double *x, break; } - /** - if (k==1){ - for (i=1; i<=x_size; i++){ - delx[i-1] *= F0[i-1]; - } + for (int i = 0; i < x_size; ++i){ + if (k == 1) { + delx[i] = -dxdF[i]*F0[i]; + } + else { + delx[i] = -toljac*p[i + 1]; + } } + + + /* + If shooting guess takes somewhere that gives an error, halve the step and try again + Copied from CLASS++ */ + double* x_inout_backup; + class_alloc(x_inout_backup,sizeof(double)*x_size,error_message); + for (int j = 0; j < x_size; j++) { + x_inout_backup[j] = x_inout[j]; + } /** Compute the jacobian of F: */ for (i=1; i<=x_size; i++){ - if (F0[i-1]<0.0) - delx[i-1] *= -1; - x_inout[i-1] += delx[i-1]; - - /** printf("x = [%f, %f], delx = [%e, %e]\n", - x_inout[0],x_inout[1],delx[0],delx[1]);*/ - class_call(func(x_inout, x_size, param, Fdel, error_message), - error_message, error_message); - /** printf("F = [%f, %f]\n",Fdel[0],Fdel[1]);*/ + int return_function = _FAILURE_; + for (int func_iter = 0; func_iter < 10; ++func_iter) { + x_inout[i - 1] = x_inout_backup[i - 1] + delx[i - 1]; + + /* + printf("Evaluating at x_inout: "); + for (int asdf = 0; asdf < x_size; asdf++) { + printf("x[%d]=%g, ", asdf, x_inout[asdf]); + } + printf("\n"); + */ + return_function = func(x_inout, x_size, param, Fdel, error_message); + *fevals += 1; + + if (return_function == _SUCCESS_) { + double max_y_diff = 0.; + for (int j = 0; j < x_size; ++j) { + double yscal = MAX(1e-50, 0.5*(fabs(Fdel[j]) + fabs(F0[j]))); + max_y_diff = MAX(max_y_diff, fabs((Fdel[j] - F0[j])/yscal)); + } + if (max_y_diff > tolF*tolF) { + //Significant difference + break; + } + else { + delx[i - 1] *= 2; + } + } + else { + delx[i - 1] *= -0.5; + } + } + if (return_function == _FAILURE_) { + class_test(1 == 1, error_message, "Jacobian computation in Newtons method failed during shooting") + } for (j=1; j<=x_size; j++) Fjac[j][i] = (Fdel[j-1]-F0[j-1])/delx[i-1]; x_inout[i-1] -= delx[i-1]; } - *fevals = *fevals + x_size; - + /* + printf("Found x_inout: "); + for (int asdf = 0; asdf < x_size; asdf++) { + printf("x[%d]=%g, ", asdf, x_inout[asdf]); + } + printf("\n"); + */ + for (i=1; i<=x_size; i++) p[i] = -F0[i-1]; //Right-hand side of linear equations. funcreturn = ludcmp(Fjac, x_size, indx, &d, lu_work); //Solve linear equations using LU decomposition. diff --git a/tools/evolver_rkdp45.c b/tools/evolver_rkdp45.c new file mode 100755 index 000000000..321a50ba2 --- /dev/null +++ b/tools/evolver_rkdp45.c @@ -0,0 +1,292 @@ +#include "evolver_rkdp45.h" + +int evolver_rkdp45( + int (*derivs)(double x,double * y,double * dy, + void * parameters_and_workspace, ErrorMsg error_message), + double t_ini, + double t_final, + double * y_inout, + int* used_in_output, + int neq, + void * parameters_and_workspace_for_derivs, + double rtol, + double minimum_variation, + int (*timescale_and_approximation)(double x, + void * parameters_and_workspace, + double * timescales, + ErrorMsg error_message), + double timestep_over_timescale, + double* t_vec, + int tres, + int (*output)(double x,double y[],double dy[],int index_x,void * parameters_and_workspace, + ErrorMsg error_message), + int (*print_variables)(double x, double y[], double dy[], void *parameters_and_workspace, + ErrorMsg error_message), + ErrorMsg error_message){ + + /** Handle options: */ + + double abstol = 1e-15; // Same as in ndf15 + int stats[3] = {0, 0, 0}; + int verbose = 0; + int output_return; + + double *dy,*err,*ynew,*ytemp, *ki; + double h,absh,hmax,errmax,errtemp,hmin,hnew; + double t,tnew; + int tdir, i, j, k, idx=0; + int s=7; + double ci[s]; + double bi[s]; + double bi_diff[s]; + double ai[s][s]; + double bi_vec_y[s],bi_vec_dy[s]; + double threshold = abstol/rtol; + int nofailed; + int done = _FALSE_; + double pow_grow=0.2; + double rh,maxtmp; + //Interpolation variables: + double i01,i02,i03; + double ixx[5][3]; + double ti,ss1,ss2,ss3,ss4,*yinterp,*dyinterp; + dy = (double *) malloc(sizeof(double)*neq); + ytemp = (double *) malloc(sizeof(double)*neq); + yinterp = (double *) malloc(sizeof(double)*neq); + dyinterp = (double *) malloc(sizeof(double)*neq); + ynew = (double *) malloc(sizeof(double)*neq); + err = (double *) malloc(sizeof(double)*neq); + pow_grow = 0.2; + ki = (double *) malloc(sizeof(double)*s*neq); + /** Set method parameters for Runge-Kutta Dormand-Prince method: + ------------------------------------------------------------------ + */ + ci[0] = 0.0; ci[1] = 0.2; ci[2] = 0.3; ci[3] = 0.8; + ci[4] = 8.0/9.0; ci[5] = 1.0; ci[6] = 1.0; + bi[0] = 35.0/384.0; bi[1] = 0.0; bi[2] = 500.0/1113.0; + bi[3] = 125.0/192.0; bi[4] = -2187.0/6784.0; bi[5] = 11.0/84.0; bi[6] = 0.0; + bi_diff[0] = 71.0/57600.0; bi_diff[1] = 0.0; bi_diff[2] = -71.0/16695.0; + bi_diff[3] = 71.0/1920.0; bi_diff[4] = -17253.0/339200.0; + bi_diff[5] = 22.0/525.0; bi_diff[6] = -1.0/40.0; + ai[1][0] = 0.2; + ai[2][0] = 3.0/40.0; ai[2][1] = 9.0/40.0; + ai[3][0] = 44.0/45.0; ai[3][1] = -56.0/15.0; ai[3][2] = 32.0/9.0; + ai[4][0] = 19372.0/6561.0; ai[4][1] = -25360.0/2187.0; + ai[4][2] = 64448.0/6561.0; ai[4][3] = -212.0/729.0; + ai[5][0] = 9017.0/3168.0; ai[5][1] = -355.0/33.0; ai[5][2] = 46732.0/5247.0; + ai[5][3] = 49.0/176.0; ai[5][4] = -5103.0/18656.0; + ai[6][0] = 35.0/384.0; ai[6][1] = 0.0; ai[6][2] = 500.0/1113.0; + ai[6][3] = 125.0/192.0; ai[6][4] = -2187.0/6784.0; ai[6][5] = 11.0/84.0; + ixx[0][0] = 1500.0/371.0; ixx[0][1] = -1000.0/159.0; ixx[0][2] = 1000.0/371.0; + ixx[1][0] = -125.0/32.0; ixx[1][1] = 125.0/12.0; ixx[1][2] = -375.0/64.0; + ixx[2][0] = 9477.0/3392.0; ixx[2][1] = -729.0/106.0; ixx[2][2] = 25515.0/6784.0; + ixx[3][0] = -11.0/7.0; ixx[3][1] = 11.0/3.0; ixx[3][2] = -55.0/28.0; + ixx[4][0] = 1.5; ixx[4][1] = -4.0; ixx[4][2] = 2.5; + i01 = -183.0/64.0; i02=37.0/12.0; i03 = -145.0/128.0; + /** + Done setting method parameters. + */ + + t = t_ini; + //initialise ki + class_call((*derivs)(t,y_inout,ki,parameters_and_workspace_for_derivs,error_message),error_message,error_message); + hmin = 100.0*DBL_MIN*fabs(t); + hmax = fabs(t_final-t_ini)/10.0; + if (t_vec!=NULL) + absh = MIN(hmax,fabs(t_vec[1]-t_vec[0])); + else + absh = hmax; + if (absh==0.0) + absh = hmax; + //Compute h_initial: + for (k=0,rh=0.0; k1.0) + absh = 1.0/rh; + if (t_final>t_ini) + tdir = 1; + else + tdir = -1; + + hnew = absh*tdir; + h = hnew; + //Find current index: + if (t_vec != NULL){ + //Output at specified points. + for(idx = 0; (t_vec[idx]-t)*tdir<0.0; idx++); + } + nofailed = _TRUE_; + + while ((t-t_final)*tdir<0.0){ + h = hnew; + hmin = 100.0*DBL_MIN*fabs(t); + if (fabs(h)0.9*fabs(t_final-t)) + h = t_final-t; + //Try to take a step h. + for (k=0; k2){ + printf("Evaluating ODE at t=%g, ci[i] = %g. h=%g\n", + t+ci[i]*h,ci[i],h); + printf("y_inout = [%g,%g]. ytemp = [%g,%g]\n", + y_inout[0],y_inout[1],ytemp[0],ytemp[1]); + } + class_call((*derivs)(t+ci[i]*h,ytemp,ki+i*neq,parameters_and_workspace_for_derivs,error_message),error_message,error_message); + // Update ynew and err: + for (k=0; k3) + printf("Finished loop over i, new y has been found.\n"); + // Got new y and error estimate. + for (k=0,errmax = 0.0; kerrmax){ + errmax = errtemp; + } + } + if (verbose>3) + printf("h: %g, errmax = %g\n",h,errmax); + if (errmax>rtol){ + if (verbose>4) + printf("Step rejected..\n"); + stats[1]++; + //Step rejected. + if (nofailed == _TRUE_){ + hnew = tdir*MAX(hmin, fabs(h) * MAX(0.1, 0.8*pow(rtol/errmax,pow_grow))); + } + else{ + hnew = tdir*MAX(hmin,0.5*fabs(h)); + nofailed = _FALSE_; + } + } + else{ + //Step accepted. + stats[0]++; + if (print_variables!=NULL){ + class_call((*print_variables)(t+h,ynew,ki+6*neq, + parameters_and_workspace_for_derivs,error_message), + error_message,error_message); + } + if (verbose>1) + printf("Step accepted. t=%g, h=%g\n",t,h); + nofailed = _TRUE_; + + hnew = tdir*MAX(hmin, fabs(h) * MAX(0.1, 0.8*pow(rtol/errmax,pow_grow))); + tnew = t+h; + //Do we need to write output? + if (t_vec==NULL){ + //Refined output + for (idx=1; idx=0.0); idx++){ + if (tnew==t_vec[idx]){ + //We have hit the point exactly. Use ynew and dy=ki+6*neq + class_evolver_output((*output)(tnew,ynew,ki+6*neq,idx,parameters_and_workspace_for_derivs,error_message), + error_message,error_message); + } + else{ + //Interpolate to get output using the information in the ki-matrix: + ti = t_vec[idx]; + ss1 = (ti-t)/h; ss2=ss1*ss1; ss3=ss2*ss1; ss4=ss2*ss2; + bi_vec_y[0] = ss1+i01*ss2+i02*ss3+i03*ss4; + bi_vec_dy[0] = 1.0+i01*2.0*ss1+i02*3.0*ss2+i03*4.0*ss3; + //bi_vec_y[1] = 0.0; bi_vec_dy[1] = 0.0; + for (i=2; i<7; i++){ + bi_vec_y[i] = ixx[i-2][0]*ss2+ixx[i-2][1]*ss3+ixx[i-2][2]*ss4; + bi_vec_dy[i] = ixx[i-2][0]*2*ss1+ixx[i-2][1]*3*ss2+ixx[i-2][2]*4*ss3; + } + for (k=0; k0) + printf(" Successful steps: %d\n Failed steps: %d\n Function evaluations: %d\n", + stats[0],stats[1],stats[2]); + free(dy); + free(ynew); + free(ytemp); + free(ki); + free(err); + return _SUCCESS_; +} diff --git a/tools/parser.c b/tools/parser.c index 602e2b729..93fed3348 100644 --- a/tools/parser.c +++ b/tools/parser.c @@ -738,3 +738,37 @@ int parser_check_options(char * strinput, char ** options, int N_options, int* v return _SUCCESS_; } + +int parser_extend(struct file_content * pfc, int N_extend, ErrorMsg errmsg) { + // Append N_extend empty entries in the vectors of pfc + pfc->size += N_extend; + class_realloc(pfc->name, pfc->name, pfc->size*sizeof(FileArg), errmsg); + class_realloc(pfc->value, pfc->value, pfc->size*sizeof(FileArg), errmsg); + class_realloc(pfc->read, pfc->read, pfc->size*sizeof(short), errmsg); + for (int index = pfc->size - N_extend; index < pfc->size; index++) { + pfc->name[index][0] = '\0'; + pfc->value[index][0] = '\0'; + pfc->read[index] = _FALSE_; + } + return _SUCCESS_; +} + +int parser_copy(struct file_content * pfc_source, struct file_content * pfc_destination, int index_start, int index_end) { + // Copy the entries from index_start to index_end from pfc_source to pfc_destination + memcpy(pfc_destination->name + index_start, pfc_source->name + index_start, (index_end - index_start)*sizeof(FileArg)); + memcpy(pfc_destination->value + index_start, pfc_source->value + index_start, (index_end - index_start)*sizeof(FileArg)); + memcpy(pfc_destination->read + index_start, pfc_source->read + index_start, (index_end - index_start)*sizeof(short)); + return _SUCCESS_; +} + +int parser_init_from_pfc(struct file_content * pfc_source, struct file_content * pfc_destination, ErrorMsg errmsg) { + class_call(parser_init(pfc_destination, + pfc_source->size, + pfc_source->filename, + errmsg), + errmsg,errmsg); + parser_copy(pfc_source, pfc_destination, 0, pfc_source->size); + return _SUCCESS_; +} + +