From bbbb10d47148d7a855a08d5d883b69ecbeec80e3 Mon Sep 17 00:00:00 2001 From: bastiencarreres Date: Tue, 30 Apr 2024 11:23:31 -0700 Subject: [PATCH 1/9] debug --- flip/power_spectra/class_engine.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/flip/power_spectra/class_engine.py b/flip/power_spectra/class_engine.py index e61a742..5aa53dd 100644 --- a/flip/power_spectra/class_engine.py +++ b/flip/power_spectra/class_engine.py @@ -138,27 +138,25 @@ def compute_power_spectrum( ) raise error - power_spectrum_linear, power_spectrum_non_linear = [], [] + power_spectrum_linear, power_spectrum_non_linear = np.empty((2, number_points)) - if non_linear_model is None: - power_spectrum_non_linear = None - - for k in wavenumber: - power_spectrum_linear.append( - model.pk_lin(k * model.h(), redshift) * model.h() ** 3 - ) + for i, k in enumerate(wavenumber): + power_spectrum_linear[i] = model.pk_lin(k * model.h(), redshift) * model.h()**3 + if non_linear_model is not None: - power_spectrum_non_linear.append( - model.pk(k * model.h(), redshift) * model.h() ** 3 - ) + power_spectrum_non_linear[i] = model.pk(k * model.h(), redshift) * model.h()**3 + fs8_fiducial = get_fiducial_fs8(model, redshift) s8_fiducial = get_fiducial_s8(model, redshift) fiducial = {"fsigma_8": fs8_fiducial, "sigma_8": s8_fiducial} + if non_linear_model is None: + power_spectrum_non_linear = None + return ( wavenumber, - np.array(power_spectrum_linear), - np.array(power_spectrum_non_linear), + power_spectrum_linear, + power_spectrum_non_linear, fiducial, ) From 27ebd81158e6c9372caf0c48930e5fc37b50db08 Mon Sep 17 00:00:00 2001 From: bastiencarreres Date: Wed, 1 May 2024 12:32:59 -0700 Subject: [PATCH 2/9] change bel functions, add doc --- docs/power_spectra.rst | 20 ++++++++ flip/__init__.py | 2 +- flip/power_spectra/__init__.py | 1 + flip/power_spectra/models.py | 48 +++++++++++-------- .../power_spectra_generator.py | 11 ++--- 5 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 docs/power_spectra.rst rename flip/{ => power_spectra}/power_spectra_generator.py (93%) diff --git a/docs/power_spectra.rst b/docs/power_spectra.rst new file mode 100644 index 0000000..a23804e --- /dev/null +++ b/docs/power_spectra.rst @@ -0,0 +1,20 @@ +Power Spectra Generator +======================= + +You can use the `flip.power_spectra` module to compute your power spectra using the `flip.power_spectra.compute_power_spectra` function: + +``` +k, pdd, pdt, ptt = compute_power_spectra( + power_spectrum_engine, + power_spectrum_settings, + redshift, + minimal_wavenumber, + maximal_wavenumber, + number_points, + logspace=True, + normalize_power_spectrum=True, + power_spectrum_non_linear_model=None, + power_spectrum_model="linearbel", + save_path=None, +) +python``` diff --git a/flip/__init__.py b/flip/__init__.py index 7e72e61..51cf0fc 100644 --- a/flip/__init__.py +++ b/flip/__init__.py @@ -1,7 +1,7 @@ """Init file of the flip package.""" import os -from . import covariance, fitter, gridding, likelihood, power_spectra_generator, utils +from . import covariance, fitter, gridding, likelihood, utils, power_spectra __version__ = "1.0.0" __flip_dir_path__ = os.path.dirname(__file__) diff --git a/flip/power_spectra/__init__.py b/flip/power_spectra/__init__.py index 5e9284f..8664588 100644 --- a/flip/power_spectra/__init__.py +++ b/flip/power_spectra/__init__.py @@ -1,2 +1,3 @@ """Init file of the flip.power_spectra package.""" from . import class_engine, models +from .power_spectra_generator import compute_power_spectra \ No newline at end of file diff --git a/flip/power_spectra/models.py b/flip/power_spectra/models.py index d45429e..f3177c9 100644 --- a/flip/power_spectra/models.py +++ b/flip/power_spectra/models.py @@ -22,24 +22,39 @@ def bel_coefficients(sigma_8): return a1, a2, a3, invkdelta, b -def get_nonlinearbel_model( +def get_bel_model( wavenumber, power_spectrum_linear, **kwargs, ): if "sigma_8" not in kwargs.keys(): raise ValueError("Fiducial sigma_8 value is needed for nonlinearbel model") + + a1, a2, a3, invkdelta, b = bel_coefficients(kwargs["sigma_8"]) + + power_spectrum_tt = kwargs["fsigma_8"]**2 * power_spectrum_linear / kwargs["sigma_8"]**2 * np.exp( + -wavenumber * (a1 + a2 * wavenumber + a3 * wavenumber**2) + ) + + power_spectrum_mt = kwargs["fsigma_8"] / kwargs["sigma_8"] * power_spectrum_linear * np.exp(-invkdelta * wavenumber - b * wavenumber**6) + + return power_spectrum_mt, power_spectrum_tt +def get_nonlinearbel_model( + wavenumber, + power_spectrum_linear, + **kwargs, +): if "power_spectrum_non_linear" not in kwargs.keys(): raise ValueError("Non linear power spectrum is needed for nonlinearbel model") - a1, a2, a3, invkdelta, b = bel_coefficients(kwargs["sigma_8"]) - power_spectrum_tt = power_spectrum_linear * np.exp( - -wavenumber * (a1 + a2 * wavenumber + a3 * wavenumber**2) - ) - power_spectrum_mt = np.sqrt( - power_spectrum_linear * kwargs["power_spectrum_non_linear"] - ) * np.exp(-invkdelta * wavenumber - b * wavenumber**6) + power_spectrum_mt, power_spectrum_tt = get_bel_model( + wavenumber, + power_spectrum_linear, + **kwargs + ) + + power_spectrum_mt *= np.sqrt(kwargs["power_spectrum_non_linear"] / power_spectrum_linear) power_spectrum_mm = kwargs["power_spectrum_non_linear"] return power_spectrum_mm, power_spectrum_mt, power_spectrum_tt @@ -50,16 +65,11 @@ def get_linearbel_model( power_spectrum_linear, **kwargs, ): - if "sigma_8" not in kwargs.keys(): - raise ValueError("Fiducial sigma_8 value is needed for linearbel model") - - a1, a2, a3, invkdelta, b = bel_coefficients(kwargs["sigma_8"]) - power_spectrum_tt = power_spectrum_linear * np.exp( - -wavenumber * (a1 + a2 * wavenumber + a3 * wavenumber**2) - ) - power_spectrum_mt = power_spectrum_linear * np.exp( - -invkdelta * wavenumber - b * wavenumber**6 - ) + power_spectrum_mt, power_spectrum_tt = get_bel_model( + wavenumber, + power_spectrum_linear, + **kwargs + ) power_spectrum_mm = power_spectrum_linear - + return power_spectrum_mm, power_spectrum_mt, power_spectrum_tt diff --git a/flip/power_spectra_generator.py b/flip/power_spectra/power_spectra_generator.py similarity index 93% rename from flip/power_spectra_generator.py rename to flip/power_spectra/power_spectra_generator.py index aced5a8..efdb148 100644 --- a/flip/power_spectra_generator.py +++ b/flip/power_spectra/power_spectra_generator.py @@ -89,12 +89,6 @@ def compute_power_spectra( non_linear_model=power_spectrum_non_linear_model, ) - if normalize_power_spectrum: - power_spectrum_linear = power_spectrum_linear / fiducial["sigma_8"] ** 2 - if power_spectrum_non_linear is not None: - power_spectrum_non_linear = ( - power_spectrum_non_linear / fiducial["sigma_8"] ** 2 - ) power_spectrum_mm, power_spectrum_mt, power_spectrum_tt = eval( f"models.get_{power_spectrum_model}_model" @@ -105,6 +99,11 @@ def compute_power_spectra( **fiducial, ) + if normalize_power_spectrum: + power_spectrum_mm = power_spectrum_mm / fiducial["sigma_8"]**2 + power_spectrum_mt = power_spectrum_mt / (fiducial["fsigma_8"] * fiducial["sigma_8"]) + power_spectrum_tt = power_spectrum_tt / fiducial["fsigma_8"]**2 + if save_path is not None: suffix = get_power_spectrum_suffix( redshift, From cffac124a324dc4cadac47dc85893446b38d95c5 Mon Sep 17 00:00:00 2001 From: corentinravoux Date: Thu, 2 May 2024 10:37:33 +0200 Subject: [PATCH 3/9] format + autodocstring --- flip/power_spectra/models.py | 78 ++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/flip/power_spectra/models.py b/flip/power_spectra/models.py index f3177c9..19eb6c3 100644 --- a/flip/power_spectra/models.py +++ b/flip/power_spectra/models.py @@ -27,34 +27,70 @@ def get_bel_model( power_spectrum_linear, **kwargs, ): + """ + The get_bel_model function takes in the linear power spectrum, wavenumber, and sigma_8 value. + It then calculates the nonlinear matter-matter power spectrum using a fitting function from Bel et al. (2014). + The function also returns the nonlinear matter-matter cross correlation coefficient. + + Args: + wavenumber: Calculate the power spectrum + power_spectrum_linear: Calculate the nonlinear power spectrum + **kwargs: Pass a variable number of keyword arguments to a function + : Calculate the nonlinear power spectrum + + Returns: + The nonlinear matter power spectrum and the nonlinear galaxy clustering power spectrum + """ if "sigma_8" not in kwargs.keys(): raise ValueError("Fiducial sigma_8 value is needed for nonlinearbel model") - + a1, a2, a3, invkdelta, b = bel_coefficients(kwargs["sigma_8"]) - - power_spectrum_tt = kwargs["fsigma_8"]**2 * power_spectrum_linear / kwargs["sigma_8"]**2 * np.exp( - -wavenumber * (a1 + a2 * wavenumber + a3 * wavenumber**2) + + power_spectrum_tt = ( + kwargs["fsigma_8"] ** 2 + * power_spectrum_linear + / kwargs["sigma_8"] ** 2 + * np.exp(-wavenumber * (a1 + a2 * wavenumber + a3 * wavenumber**2)) + ) + + power_spectrum_mt = ( + kwargs["fsigma_8"] + / kwargs["sigma_8"] + * power_spectrum_linear + * np.exp(-invkdelta * wavenumber - b * wavenumber**6) ) - - power_spectrum_mt = kwargs["fsigma_8"] / kwargs["sigma_8"] * power_spectrum_linear * np.exp(-invkdelta * wavenumber - b * wavenumber**6) return power_spectrum_mt, power_spectrum_tt + def get_nonlinearbel_model( wavenumber, power_spectrum_linear, **kwargs, ): + """ + The get_nonlinearbel_model function returns the nonlinear power spectra for a given linear power spectrum. + + Args: + wavenumber: Get the wavenumber of the power spectrum + power_spectrum_linear: Calculate the power_spectrum_mt and power_spectrum_tt + **kwargs: Pass a variable number of keyword arguments to a function + : Get the nonlinear power spectrum + + Returns: + The nonlinear power spectrum of matter, the cross power spectrum of matter and tracers and the auto-power spectrum of tracers + + """ if "power_spectrum_non_linear" not in kwargs.keys(): raise ValueError("Non linear power spectrum is needed for nonlinearbel model") power_spectrum_mt, power_spectrum_tt = get_bel_model( - wavenumber, - power_spectrum_linear, - **kwargs - ) + wavenumber, power_spectrum_linear, **kwargs + ) - power_spectrum_mt *= np.sqrt(kwargs["power_spectrum_non_linear"] / power_spectrum_linear) + power_spectrum_mt *= np.sqrt( + kwargs["power_spectrum_non_linear"] / power_spectrum_linear + ) power_spectrum_mm = kwargs["power_spectrum_non_linear"] return power_spectrum_mm, power_spectrum_mt, power_spectrum_tt @@ -65,11 +101,21 @@ def get_linearbel_model( power_spectrum_linear, **kwargs, ): + """ + The get_linearbel_model function returns the linear BEL model for a given power spectrum. + + Args: + wavenumber: Calculate the wavenumber in h/mpc + power_spectrum_linear: Calculate the power spectrum of the matter field + **kwargs: Pass a variable number of keyword arguments to the function + : Set the value of the power spectrum + + Returns: + The linear power spectrum and the + """ power_spectrum_mt, power_spectrum_tt = get_bel_model( - wavenumber, - power_spectrum_linear, - **kwargs - ) + wavenumber, power_spectrum_linear, **kwargs + ) power_spectrum_mm = power_spectrum_linear - + return power_spectrum_mm, power_spectrum_mt, power_spectrum_tt From 65625b7d3292f512cfd757eff08ed1bace837a16 Mon Sep 17 00:00:00 2001 From: corentinravoux Date: Thu, 2 May 2024 10:37:49 +0200 Subject: [PATCH 4/9] format + fix --- flip/power_spectra/class_engine.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/flip/power_spectra/class_engine.py b/flip/power_spectra/class_engine.py index 5aa53dd..a78d6ab 100644 --- a/flip/power_spectra/class_engine.py +++ b/flip/power_spectra/class_engine.py @@ -117,7 +117,7 @@ def compute_power_spectrum( if non_linear_model is not None: power_spectrum_settings.update( { - "non_linear": non_linear_model, + "non linear": non_linear_model, } ) power_spectrum_settings.update({"z_max_pk": redshift}) @@ -141,11 +141,14 @@ def compute_power_spectrum( power_spectrum_linear, power_spectrum_non_linear = np.empty((2, number_points)) for i, k in enumerate(wavenumber): - power_spectrum_linear[i] = model.pk_lin(k * model.h(), redshift) * model.h()**3 - + power_spectrum_linear[i] = ( + model.pk_lin(k * model.h(), redshift) * model.h() ** 3 + ) + if non_linear_model is not None: - power_spectrum_non_linear[i] = model.pk(k * model.h(), redshift) * model.h()**3 - + power_spectrum_non_linear[i] = ( + model.pk(k * model.h(), redshift) * model.h() ** 3 + ) fs8_fiducial = get_fiducial_fs8(model, redshift) s8_fiducial = get_fiducial_s8(model, redshift) From 0e2cf8daf95df03489f4ef59eeb6b411050d139d Mon Sep 17 00:00:00 2001 From: corentinravoux Date: Thu, 2 May 2024 11:16:36 +0200 Subject: [PATCH 5/9] change the way the power spectrum is normalized --- flip/power_spectra/models.py | 14 +++-------- flip/power_spectra/power_spectra_generator.py | 25 ++++++++++++++----- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/flip/power_spectra/models.py b/flip/power_spectra/models.py index 19eb6c3..5db7b3f 100644 --- a/flip/power_spectra/models.py +++ b/flip/power_spectra/models.py @@ -46,18 +46,12 @@ def get_bel_model( a1, a2, a3, invkdelta, b = bel_coefficients(kwargs["sigma_8"]) - power_spectrum_tt = ( - kwargs["fsigma_8"] ** 2 - * power_spectrum_linear - / kwargs["sigma_8"] ** 2 - * np.exp(-wavenumber * (a1 + a2 * wavenumber + a3 * wavenumber**2)) + power_spectrum_tt = power_spectrum_linear * np.exp( + -wavenumber * (a1 + a2 * wavenumber + a3 * wavenumber**2) ) - power_spectrum_mt = ( - kwargs["fsigma_8"] - / kwargs["sigma_8"] - * power_spectrum_linear - * np.exp(-invkdelta * wavenumber - b * wavenumber**6) + power_spectrum_mt = power_spectrum_linear * np.exp( + -invkdelta * wavenumber - b * wavenumber**6 ) return power_spectrum_mt, power_spectrum_tt diff --git a/flip/power_spectra/power_spectra_generator.py b/flip/power_spectra/power_spectra_generator.py index efdb148..8789cad 100644 --- a/flip/power_spectra/power_spectra_generator.py +++ b/flip/power_spectra/power_spectra_generator.py @@ -6,6 +6,7 @@ _available_engines = ["class_engine"] _available_power_spectrum_model = ["linearbel", "nonlinearbel"] +_available_power_spectrum_normalizaton = ["growth_rate", "growth_amplitude"] def get_power_spectrum_suffix( @@ -56,7 +57,7 @@ def compute_power_spectra( maximal_wavenumber, number_points, logspace=True, - normalize_power_spectrum=True, + normalization_power_spectrum=None, power_spectrum_non_linear_model=None, power_spectrum_model="linearbel", save_path=None, @@ -89,7 +90,6 @@ def compute_power_spectra( non_linear_model=power_spectrum_non_linear_model, ) - power_spectrum_mm, power_spectrum_mt, power_spectrum_tt = eval( f"models.get_{power_spectrum_model}_model" )( @@ -99,10 +99,23 @@ def compute_power_spectra( **fiducial, ) - if normalize_power_spectrum: - power_spectrum_mm = power_spectrum_mm / fiducial["sigma_8"]**2 - power_spectrum_mt = power_spectrum_mt / (fiducial["fsigma_8"] * fiducial["sigma_8"]) - power_spectrum_tt = power_spectrum_tt / fiducial["fsigma_8"]**2 + if normalization_power_spectrum == "growth_rate": + power_spectrum_mm = power_spectrum_mm + power_spectrum_mt = power_spectrum_mt * ( + fiducial["fsigma_8"] / fiducial["sigma_8"] + ) + power_spectrum_tt = ( + power_spectrum_tt * (fiducial["fsigma_8"] / fiducial["sigma_8"]) ** 2 + ) + elif normalization_power_spectrum == "growth_amplitude": + power_spectrum_mm = power_spectrum_mm / fiducial["sigma_8"] ** 2 + power_spectrum_mt = power_spectrum_mt / fiducial["sigma_8"] ** 2 + power_spectrum_tt = power_spectrum_tt / fiducial["sigma_8"] ** 2 + else: + raise ValueError( + f"The normalization {normalization_power_spectrum} of the power spectrum is not available," + f"Please choose in {_available_power_spectrum_normalizaton}." + ) if save_path is not None: suffix = get_power_spectrum_suffix( From de36c80980ac8cae362e650c730dca674fc6a09f Mon Sep 17 00:00:00 2001 From: corentinravoux Date: Thu, 2 May 2024 16:54:14 +0200 Subject: [PATCH 6/9] renaming of power_spectra_generator --- flip/power_spectra/__init__.py | 3 ++- .../{power_spectra_generator.py => generator.py} | 0 scripts/flip_compute_power_spectra.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) rename flip/power_spectra/{power_spectra_generator.py => generator.py} (100%) diff --git a/flip/power_spectra/__init__.py b/flip/power_spectra/__init__.py index 8664588..71a528c 100644 --- a/flip/power_spectra/__init__.py +++ b/flip/power_spectra/__init__.py @@ -1,3 +1,4 @@ """Init file of the flip.power_spectra package.""" + from . import class_engine, models -from .power_spectra_generator import compute_power_spectra \ No newline at end of file +from .generator import compute_power_spectra diff --git a/flip/power_spectra/power_spectra_generator.py b/flip/power_spectra/generator.py similarity index 100% rename from flip/power_spectra/power_spectra_generator.py rename to flip/power_spectra/generator.py diff --git a/scripts/flip_compute_power_spectra.py b/scripts/flip_compute_power_spectra.py index e297484..cb206d6 100644 --- a/scripts/flip_compute_power_spectra.py +++ b/scripts/flip_compute_power_spectra.py @@ -1,4 +1,4 @@ -from flip import power_spectra_generator +from flip.power_spectra import generator power_spectrum_engine = "class_engine" @@ -29,7 +29,7 @@ power_spectrum_mm, power_spectrum_mt, power_spectrum_tt, -) = power_spectra_generator.compute_power_spectra( +) = generator.compute_power_spectra( power_spectrum_engine, power_spectrum_settings, redshift, From 983bbf3b8c398f362cef4934283c58a380d713bb Mon Sep 17 00:00:00 2001 From: corentinravoux Date: Thu, 2 May 2024 16:57:00 +0200 Subject: [PATCH 7/9] changing normalization default --- flip/power_spectra/generator.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/flip/power_spectra/generator.py b/flip/power_spectra/generator.py index 8789cad..76f73fd 100644 --- a/flip/power_spectra/generator.py +++ b/flip/power_spectra/generator.py @@ -6,7 +6,11 @@ _available_engines = ["class_engine"] _available_power_spectrum_model = ["linearbel", "nonlinearbel"] -_available_power_spectrum_normalizaton = ["growth_rate", "growth_amplitude"] +_available_power_spectrum_normalizaton = [ + "no_normalization", + "growth_rate", + "growth_amplitude", +] def get_power_spectrum_suffix( @@ -57,7 +61,7 @@ def compute_power_spectra( maximal_wavenumber, number_points, logspace=True, - normalization_power_spectrum=None, + normalization_power_spectrum="no_normalization", power_spectrum_non_linear_model=None, power_spectrum_model="linearbel", save_path=None, @@ -111,6 +115,8 @@ def compute_power_spectra( power_spectrum_mm = power_spectrum_mm / fiducial["sigma_8"] ** 2 power_spectrum_mt = power_spectrum_mt / fiducial["sigma_8"] ** 2 power_spectrum_tt = power_spectrum_tt / fiducial["sigma_8"] ** 2 + elif normalization_power_spectrum == "no_normalization": + True else: raise ValueError( f"The normalization {normalization_power_spectrum} of the power spectrum is not available," From e199e822d6c6a17051cea3bbe3605cfba173727c Mon Sep 17 00:00:00 2001 From: Bastien Carreres Date: Thu, 2 May 2024 11:47:14 -0400 Subject: [PATCH 8/9] Update generator.py replace True by pass --- flip/power_spectra/generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flip/power_spectra/generator.py b/flip/power_spectra/generator.py index 76f73fd..2109dc2 100644 --- a/flip/power_spectra/generator.py +++ b/flip/power_spectra/generator.py @@ -116,7 +116,7 @@ def compute_power_spectra( power_spectrum_mt = power_spectrum_mt / fiducial["sigma_8"] ** 2 power_spectrum_tt = power_spectrum_tt / fiducial["sigma_8"] ** 2 elif normalization_power_spectrum == "no_normalization": - True + pass else: raise ValueError( f"The normalization {normalization_power_spectrum} of the power spectrum is not available," From 31be7cde2f9971864431851886a05578d7175f3c Mon Sep 17 00:00:00 2001 From: bastiencarreres Date: Tue, 14 May 2024 08:55:38 -0700 Subject: [PATCH 9/9] update docstring --- flip/power_spectra/generator.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/flip/power_spectra/generator.py b/flip/power_spectra/generator.py index 2109dc2..157a8a6 100644 --- a/flip/power_spectra/generator.py +++ b/flip/power_spectra/generator.py @@ -66,6 +66,30 @@ def compute_power_spectra( power_spectrum_model="linearbel", save_path=None, ): + """Compute the power spectrum. + + Args: + power_spectrum_engine (str): engine to use to compute the power spectrum, see _available_engines. + power_spectrum_settings (dic): configuration for the engine. + redshift (float): the redshift at which compute the power spectrum. + minimal_wavenumber (float): minimum k in h/Mpc. + maximal_wavenumber (float): maximum k in h/Mpc. + number_points (int): Sampling of the power spectrum. + logspace (bool, optional): Sample the power spectrum in logspace or linspace. Defaults to True. + normalization_power_spectrum (str, optional): which normalisation to use. Defaults to "no_normalization". + Available options are: "no_normalization", "growth_rate" or "growth_amplitude". + power_spectrum_non_linear_model (str, optional): Non-linear model to compute. Defaults to None. + power_spectrum_model (str, optional): Non-linear model to apply to the computed power spectrum, see _available_power_spectrum_model. Defaults to "linearbel". + save_path (str, optional): Path to save the computed power spectrum. Defaults to None. + + Raises: + ValueError: power_spectrum_engine is not available + ValueError: power_spectrum_model is not available + ValueError: _description_ + + Returns: + _type_: _description_ + """ if power_spectrum_engine not in _available_engines: raise ValueError( f"The engine {power_spectrum_engine} is not available"