Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fast P(k,z) access #145

Open
plaszczy opened this issue Mar 24, 2017 · 15 comments
Open

fast P(k,z) access #145

plaszczy opened this issue Mar 24, 2017 · 15 comments

Comments

@plaszczy
Copy link

Dear Class support,
I would like to gain on the speed of P(k,z) computations (which is too low by default) and wonder how to do that efficiently so I have a few questions:

  • is it possible to specify externally the k node values used ?. Is there a dedicated function for that? (is it good idea? it may depend interpolation scheme used)
  • is a call to Pk(vec k,z) faster than individual P(k_i,z) ones?
    -there is a z_max_pk (that I set) : is there a z_min_pk one?
    -how is performed the P(k,z) evolution in z? (in which part of the code?)

any other idea?
thanks, my best
stephane

@ThomasTram
Copy link
Collaborator

Hi Stephane

Are you calling CLASS through the Python wrapper, the C++ wrapper or directly through C?

Cheers,
Thomas

@plaszczy
Copy link
Author

Hi Thomas,
throught the standard C API.
I try to understand how p(k,z) is computed; actually what I need is fast access to p(k,z) but for a fixed z . it looks to me that this call performes a 2D spline interpolation whicle I only need 1D (in k)
Is there some explanation somewhere on this module?
thanks
stephane

@ThomasTram
Copy link
Collaborator

Hi again

Computing P(k,z) requires most of the CLASS modules except for the transfer module (that computes transfer functions in harmonic space) the lensing module (that computes CMB lensing) and the non-linear module (unless halofit is required). This takes of the order 1 second. After this computation the P(k,z) can be recovered using spectra_pk_at_z(), but the time needed for doing spline interpolation in this function call is completely negligible compared to running CLASS. But if you want, you can directly access P(k,z) for the computed (k,z)-values using the array psp->ln_pk[].

A real speedup in this computation can be obtained by
*) Not asking for Cls, in order to skip the transfer module.
*) Reducing the number of computed k-values, especially at large k.

For the last part, you can play with the settings mentioned in this issue #32.

Cheers,
Thomas

@plaszczy
Copy link
Author

thanks Thomas,
actually my limitation really comes from calling spectra_pk_at_k_and_z not from computing the table ( I have many many calls). Is there a way to speed up the interpolation?
cheers
stephane

@ThomasTram
Copy link
Collaborator

Hi again

Okay, you must have many k-values then! But then spectra_pk_at_k_and_z() is indeed pretty slow, since for each k, the k-array at the given tau is constructed from interpolation and then splined. You will need to write a new fast function, but first a question: Do you know all the k-values you want to compute P(k) from the beginning, or do you generate them on the fly? (The latter would be the case if you are for instance doing adaptive integration in k...)

Cheers,
Thomas

@plaszczy
Copy link
Author

right, this is for tomography where up to 10^10 P(k,z) values may be required. But good news k and z
are fixed and known
cheers
stephane

@ThomasTram
Copy link
Collaborator

ThomasTram commented Mar 31, 2017

Hi Stephane

I have written two functions that should solve your problem, you can find them in the attached .txt file. (I have done some testing, but not extensive, so I apologise in advance for any bugs or weird behaviour.) This is exceptional of course, normally I would just provide some hints to the solution :)

The two functions are
´´´´
int spectra_fast_pk_at_kvec(
struct background * pba,
struct spectra * psp,
double * kvec,
int kvec_size,
double * pk_tot_out /* (must be already allocated with kvec_sizepsp) /
);
''''
and
´´´´
int spectra_fast_pk_at_kvec_and_zvec(
struct background * pba,
struct spectra * psp,
double * kvec,
int kvec_size,
double * zvec,
int zvec_size,
double * pk_tot_out /
(must be already allocated with kvec_size
zvec_size) */
''''
The first one returns P(k,z_class) on the grid of log(tau) values found in psp->ln_tau[]. This array is computed by CLASS, and the largest values is slightly before the maximum z required in input. The second function is probably what you want, since it is interpolated in zvec as well. So you just pass the z_array and the k_array you want and it is interpolated.

If you read the code you can see that I made several tricks to increase the interpolation speed. Let me know how it works.

Cheers,
Thomas

PS You need to add the functions to spectra.c and you need to add the functions to spectra.h.

pkfunctions.txt

@plaszczy
Copy link
Author

plaszczy commented Mar 31, 2017 via email

@plaszczy
Copy link
Author

plaszczy commented Mar 31, 2017 via email

@plaszczy
Copy link
Author

plaszczy commented Apr 1, 2017

OK I cured my problem: I was using a z_max_pk =1 in my test (and shoud not with spectra_fast_pk_at_kvec). I guess the output is of size kvecsize*psp->ln_tau_size right?
This one works very well (20 times faster!) and gives the same results than the standard call.
congrats

@ThomasTram
Copy link
Collaborator

That's correct. For z_max_pk of 100, psp->ln_tau_size is roughly 450. I think the other function is probably the one you want since you can choose the z-vector yourself. (So this function is potentially much faster if you need less redshifts.)

Cheers,
Thomas

@plaszczy
Copy link
Author

plaszczy commented Apr 4, 2017

OK I confirm the other routine works also well (and is probably less dangerous while as efficient)
I've done a "nl" version (only modifying only the call to spectra_pk_nl_at_z, looks enough could you confirm?

Any chance the code enters the master (or other) branch? it might interest others.
thanks again
stephane

@ThomasTram
Copy link
Collaborator

Hi Stephane

Yes that should be fine. I think this new method should be implemented in the master branch in the next release. I will leave this issue open so that I remember!

Cheers,
Thomas

@plaszczy
Copy link
Author

Hi Thomas,
I discovered a slight difference between the fast version you provided and the standard one:
below the kmin cutoff (around 1e-5) the former goes directly to 0, while latter is smoothly extrapolated.
This cause problems when one computes integrals with bessel functions (as Cl). So
-is there a way to have some extrapolation in the fast version?
-is there a way to specify (lower) the kmin cutoff?

thanks,
cheers
stephane

@plaszczy
Copy link
Author

Hi Thomas,
I don't think actually there is much problem with the kmin cutoff.
It looks I am getting into troubles because I am using CLASS with several threads.
Thread1 computes P(k,z). however thread2 is computing another quantity at z2 that modifies the ba structure so that P(k,z1) gets screwed up. Can you confirm that the function makes indeed use of ba?

I could copy the ba structure at the start of the Pk function so that it does not change during the computation. Is there a way to do this easily?
cheers
stephane

lesgourg pushed a commit that referenced this issue Feb 20, 2024
* Fixing 142 by using cubic interpolation of lnPk

* Making makefile compatible with the pypi installation by promoting the CLASSDIR to an environment variable that can be passed during installation

---------

Co-authored-by: schoeneberg <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants