You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Julia is column-major; make sure innermost loop indices appear first in slice expressions (https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-column-major)
τs =collect(τs) # force array to avoid floating point errors with ranges in following χs due to (e.g. tiny negative χ)
94
99
χs = τs[end] .- τs
95
100
Is =similar(Ss, length(ks), length(ls))
96
101
102
+
verbose && l_limber <typemax(Int) &&println("Using Limber approximation for l ≥ $l_limber")
103
+
97
104
#TODO: skip and set jl to zero if l ≳ kτ0 or another cutoff?
98
105
@tasksfor il ineachindex(ls) # parallellize independent loop iterations
99
106
@localbegin# define task-local values (declared once for all loop iterations)
@@ -103,13 +110,30 @@ function los_integrate(Ss::AbstractMatrix{T}, ls::AbstractVector, τs::AbstractV
103
110
verbose &&print("\rLOS integrating with l = $l")
104
111
for ik ineachindex(ks)
105
112
k = ks[ik]
106
-
for iτ ineachindex(τs)
107
-
S = Ss[iτ,ik]
108
-
χ = χs[iτ]
109
-
kχ = k * χ
110
-
∂I_∂τ[iτ] = S *jl(l, kχ) #TODO: rewrite LOS integral to avoid evaluating jl with dual numbers? # TODO: rewrite LOS integral with y = kτ0 and x=τ/τ0 to cache jls independent of cosmology
113
+
if l ≥ l_limber
114
+
χ = (l+1/2) / k
115
+
if χ > χs[1]
116
+
# χ > χini > χrec, so source function is definitely zero
117
+
S =0.0
118
+
else
119
+
# interpolate between two closest points in saved array
120
+
iχ₋ =searchsortedfirst(χs, χ; rev =true)
121
+
iχ₊ = iχ₋ -1
122
+
χ₋, χ₊ = χs[iχ₋], χs[iχ₊] # now χ₋ < χ < χ₊
123
+
S₋, S₊ = Ss[iχ₋,ik], Ss[iχ₊,ik]
124
+
S = S₋ + (S₊-S₋) * (χ-χ₋) / (χ₊-χ₋)
125
+
end
126
+
I =√(π/(2l+1)) * S / k
127
+
else
128
+
for iτ ineachindex(τs)
129
+
S = Ss[iτ,ik]
130
+
χ = χs[iτ]
131
+
kχ = k * χ
132
+
∂I_∂τ[iτ] = S *jl(l, kχ) #TODO: rewrite LOS integral to avoid evaluating Rl with dual numbers? # TODO: rewrite LOS integral with y = kτ0 and x=τ/τ0 to cache jls independent of cosmology
133
+
end
134
+
I =integrate(τs, ∂I_∂τ; integrator) # integrate over τ # TODO: add starting I(τini) to fix small l?
111
135
end
112
-
Is[ik,il] =integrate(τs, ∂I_∂τ; integrator) # integrate over τ # TODO: add starting I(τini) to fix small l?
136
+
Is[ik,il] =I
113
137
end
114
138
end
115
139
verbose &&println()
@@ -181,46 +205,67 @@ function spectrum_cmb(ΘlAs::AbstractMatrix, ΘlBs::AbstractMatrix, P0s::Abstrac
Compute the CMB power spectra `modes` (`:TT`, `:EE`, `:TE` or an array thereof) ``C_l^{AB}``'s at angular wavenumbers `ls` from the cosmological solution `sol`.
210
+
Compute angular CMB power spectra ``Cₗᴬᴮ`` at angular wavenumbers `ls` from the cosmological problem `prob`.
211
+
The requested `modes` are specified as a vector of symbols in the form `:AB`, where `A` and `B` are `T` (temperature), `E` (E-mode polarization) or `ψ` (lensing).
187
212
If `unit` is `nothing` the spectra are of dimensionless temperature fluctuations relative to the present photon temperature; while if `unit` is a temperature unit the spectra are of dimensionful temperature fluctuations.
213
+
Returns a matrix of ``Cₗ`` if `normalization` is `:Cl`, or ``Dₗ = l(l+1)/2π`` if `normalization` is `:Dl`.
214
+
215
+
The lensing line-of-sight integral uses the Limber approximation for `l ≥ l_limber`.
# check if interpolation is close enough for all sources
243
243
# (equivalent to finding the source grid of each source separately)
244
-
@syncif!all(isapprox(S[iS, :], Sint[iS, :]; kwargs...) for iS in1:size(Ss, 1))
244
+
@syncif!all(isapprox(S[iS, begin:end-1], Sint[iS, begin:end-1]; kwargs...) for iS in1:size(Ss, 1))# exclude χ = 0 from comparison, where some sources diverge with 1/χ
245
245
@spawnsource_grid_refine(i1, i, ks, Ss, Sk, savelock; verbose, kwargs...) # refine left subinterval
0 commit comments