CosmoBolognaLib
Free Software C++/Python libraries for cosmological calculations
CAMBinterface.f90
1 ! *****************************************************************
2 ! Copyright (C) 2022 by Federico Marulli and Giorgio Lesci *
3 ! federico.marulli3@unibo.it *
4 ! *
5 ! This program is free software; you can redistribute it and/or *
6 ! modify it under the terms of the GNU General Public License as *
7 ! published by the Free Software Foundation; either version 2 of *
8 ! the License, or (at your option) any later version. *
9 ! *
10 ! This program is distributed in the hope that it will be useful, *
11 ! but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 ! GNU General Public License for more details. *
14 ! *
15 ! You should have received a copy of the GNU General Public *
16 ! License along with this program; if not, write to the Free *
17 ! Software Foundation, Inc., *
18 ! 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ! *****************************************************************
20 
21 ! CAMB interface for C++
22 ! Author: Giorgio Lesci
23 
24 module cambinterface
25  use camb
26  use darkenergyppf
27  use quintessence
28  use recombination
29  implicit none
30 
31 contains
32 
33  ! »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
34 
35  function getcambparams () RESULT(params) bind(C, NAME='GetCAMBparams')
36 
37  use, intrinsic :: iso_c_binding, only: c_ptr, c_loc
38  type(c_ptr) :: params
39  type(CAMBparams), pointer :: p
40 
41  allocate(p)
42 
43  ! Use the C address as an opaque handle
44  params = c_loc(p)
45 
46  end function getcambparams
47 
48  ! »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
49 
50  function getcambdata () RESULT(data) bind(C, NAME='GetCAMBdata')
51 
52  use, intrinsic :: iso_c_binding, only: c_ptr, c_loc
53  type(c_ptr) :: data
54  type(CAMBdata), pointer :: pp
55 
56  allocate(pp)
57 
58  ! Use the C address as an opaque handle
59  data = c_loc(pp)
60 
61  end function getcambdata
62 
63  ! »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
64 
65  subroutine setcambparams (params, ombh2, omch2, omnuh2, massless_nu, massive_nu, neutrino_hierarchy, omk, H0, dark_energy_model, w, wa, tau, cs2_lam, T_cmb, helium_fraction) bind(C, NAME='SetCAMBparams')
66 
67  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer, c_double, c_int
68  type(c_ptr), intent(in), value :: params
69  real(c_double), intent(in), value :: ombh2, omch2, omnuh2, massless_nu, omk, H0, w, wa, tau, T_cmb, helium_fraction, cs2_lam
70  integer(c_int), intent(in), value :: massive_nu, neutrino_hierarchy, dark_energy_model
71  real*8 :: omnuh2_sterile
72  type(CAMBparams), pointer :: p
73 
74  call c_f_pointer(params, p)
75 
76  call camb_setdefparams(p)
77 
78  p%ombh2 = ombh2
79  p%omch2 = omch2
80  p%omk = omk
81  p%H0 = h0
82  p%TCMB = t_cmb
83  p%Yhe = helium_fraction
84 
85  select type(reion=>p%Reion)
86  class is (ttanhreionization)
87  reion%Reionization = .false.
88  reion%use_optical_depth = .true.
89  reion%optical_depth = tau
90  reion%delta_redshift = 1.5
91  reion%fraction = -1
92  reion%helium_redshift = 3.5
93  reion%helium_delta_redshift = 0.4
94  reion%helium_redshiftstart = reion%helium_redshift + 5*reion%helium_delta_redshift
95  end select
96 
97  select type(recomb=>p%Recomb)
98  class is (trecfast)
99  recomb%RECFAST_fudge_He = 0.86
100  recomb%RECFAST_Heswitch = 6
101  recomb%RECFAST_Hswitch = .true.
102  recomb%RECFAST_fudge = 1.14
103  if (recomb%RECFAST_Hswitch) then
104  recomb%RECFAST_fudge = recomb%RECFAST_fudge - (1.14_dl - (1.105d0 + 0.02d0))
105  end if
106  end select
107 
108  do_bispectrum = .false.
109 
110  p%Scalar_initial_condition = 1 ! adiabatic initial perturbations
111 
112  ! Neutrinos settings
113  omnuh2_sterile = 0.0
114  p%share_delta_neff = .false.
115  p%MassiveNuMethod = 1
116  call cambparams_setneutrinohierarchy(p, omnuh2, omnuh2_sterile, massless_nu+massive_nu, neutrino_hierarchy, massive_nu)
117 
118  ! Dark Energy settings
119  if (allocated(p%DarkEnergy)) deallocate(p%DarkEnergy)
120  if (dark_energy_model == 0) then
121  allocate (tdarkenergyfluid::p%DarkEnergy)
122  else if (dark_energy_model == 1) then
123  allocate (tdarkenergyppf::p%DarkEnergy)
124  else if (dark_energy_model == 2) then
125  allocate (taxioneffectivefluid::p%DarkEnergy)
126  else if (dark_energy_model == 3) then
127  allocate (tearlyquintessence::p%DarkEnergy)
128  else
129  error stop 'Unknown dark energy model!'
130  end if
131 
132  select type(darkenergy=>p%DarkEnergy)
133  class is (tdarkenergyeqnofstate)
134  darkenergy%no_perturbations = .false. ! don't change this: no perturbations is unphysical
135  darkenergy%use_tabulated_w = .false. ! avoid tabulated w
136  darkenergy%w_lam = w
137  darkenergy%wa = wa
138  darkenergy%cs2_lam = cs2_lam
139  end select
140 
141  ! Additional settings to enhance performance
142  p%Accuracy%AccuratePolarization = .false.
143  p%Accuracy%AccurateBB = .false.
144  p%Accuracy%AccurateReionization = .false.
145  p%Accuracy%AccuracyBoost = 1 ! Increase to decrease time steps, use more k values, etc.; decrease to speed up at cost of worse accuracy. Suggest 0.8 to 3.
146  p%Accuracy%lAccuracyBoost = 1 ! Larger to keep more terms in the hierarchy evolution
147  p%Accuracy%lSampleBoost = 1
148 
149  p%Max_l = 2200
150  p%Min_l = 2
151  p%Max_l_tensor = 1500
152  p%Max_eta_k_tensor = 3000
153 
154  p%WantDerivedParameters = .false.
155 
156  p%WantScalars = .false.
157  p%WantTensors = .false.
158  p%WantVectors = .false.
159  p%WantTransfer = .true.
160 
161  p%Reion%Reionization = .false.
162  p%Want_CMB = .false.
163  p%Want_CMB_lensing = .false.
164  p%DoLensing = .false.
165  p%WantCls = .false.
166 
167  p%DoLateRadTruncation = .true.
168  p%Evolve_baryon_cs = .false.
169  p%Evolve_delta_xe = .false.
170  p%Evolve_delta_Ts =.false.
171  p%Do21cm = .false.
172  p%transfer_21cm_cl = .false.
173  p%Log_lvalues = .false.
174  p%use_cl_spline_template = .true.
175 
176  end subroutine setcambparams
177 
178  ! »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
179 
180  subroutine setcambpk (params, redshift, ns, As, pivot_scalar, accurate_massive_nu, kmax, nonlinear) bind(C, NAME='SetCAMBPk')
181 
182  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer, c_double, c_bool
183  type(c_ptr), intent(in), value :: params
184  real(c_double), intent(in), value :: redshift, ns, As, pivot_scalar, kmax
185  logical(c_bool), intent(in), value :: accurate_massive_nu, nonlinear
186  type(CAMBparams), pointer :: p
187 
188  call c_f_pointer(params, p)
189 
190  if (nonlinear) then
191  p%NonLinear = 1
192  end if
193 
194  ! Set InitialPower and Transfer parameters
195  select type(initpower=>p%InitPower)
196  class is (tinitialpowerlaw)
197  initpower%As = as
198  initpower%ns = ns
199  initpower%pivot_scalar = pivot_scalar
200  initpower%r = 0
201  initpower%At = 0
202  end select
203 
204  p%Transfer%PK_num_redshifts = 1
205  p%Transfer%PK_redshifts(1) = redshift
206  p%Transfer%kmax = kmax / (p%H0 / 100.)
207 
208  ! Additional settings for managing performances
209  p%Transfer%high_precision = .false.
210  p%Transfer%accurate_massive_neutrinos = accurate_massive_nu
211  p%Transfer%k_per_logint = 0
212 
213  end subroutine setcambpk
214 
215  ! »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
216 
217  subroutine getcambresults (params, data) bind(C, NAME='GetCAMBresults')
218 
219  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer, c_bool
220  type(c_ptr), intent(in), value :: params, data
221  type(CAMBparams), pointer :: p
222  type(CAMBdata), pointer :: pp
223  integer :: error
224 
225  call c_f_pointer(params, p)
226  call c_f_pointer(data, pp)
227 
228  if (cambparams_validate(p) .eqv. .false.) then
229  error stop 'CAMB stopped'
230  end if
231 
232  error = 0
233  threadnum = 1
234  transfer_power_var = 7
235  pp%num_transfer_redshifts = 1
236 
237  !feedbacklevel = 1
238  !debugmsgs = .true.
239  call camb_getresults(pp, p, error, .true., .true.)
240 
241  end subroutine getcambresults
242 
243  ! »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
244 
245  subroutine getcambpk (data, Pk_out, minkh, dlnkh, npoints) bind(C, NAME='GetCAMBPk')
246 
247  use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer, c_double, c_int
248  type(c_ptr), intent(in), value :: data
249  real(c_double), intent(in), value :: minkh, dlnkh
250  real(c_double) :: Pk_out(npoints)
251  integer(c_int), intent(in), value :: npoints
252  real(dl) :: Pk(npoints)
253  integer :: var, i
254  type(CAMBdata), pointer :: pp
255 
256  call c_f_pointer(data, pp)
257 
258  var = transfer_power_var
259  call transfer_getmatterpowerd(pp, pp%MT, pk, 1, minkh, dlnkh, npoints, var, var)
260 
261  do i=1, npoints+1, 1
262  pk_out(i) = pk(i)
263  end do
264  return
265 
266  end subroutine getcambpk
267 
268  ! »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
269 
270  subroutine releasecambparams (params) bind(C, name='ReleaseCAMBparams')
271 
272  use, intrinsic :: iso_c_binding, only : c_ptr, c_f_pointer
273  type(c_ptr), intent(in), value :: params
274  type(CAMBparams), pointer :: p
275 
276  call c_f_pointer(params, p)
277  deallocate(p)
278 
279  end subroutine releasecambparams
280 
281  ! »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
282 
283  subroutine releasecambdata (data) bind(C, name='ReleaseCAMBdata')
284 
285  use, intrinsic :: iso_c_binding, only : c_ptr, c_f_pointer
286  type(c_ptr), intent(in), value :: data
287  type(CAMBdata), pointer :: pp
288 
289  call c_f_pointer(data, pp)
290  deallocate(pp)
291 
292  end subroutine releasecambdata
293 
294 end module cambinterface