diff --git a/benchmarks/test_ptpk.py b/benchmarks/test_ptpk.py index d46ec1544..cc06d1747 100644 --- a/benchmarks/test_ptpk.py +++ b/benchmarks/test_ptpk.py @@ -3,7 +3,6 @@ import pyccl as ccl import pyccl.nl_pt as pt import pytest -from contextlib import nullcontext # Set cosmology COSMO = ccl.Cosmology(Omega_c=0.25, Omega_b=0.05, @@ -50,8 +49,7 @@ def test_pt_pk(comb): ptt1 = ptt[t1] ptt2 = ptt[t2] - with pytest.warns(ccl.CCLWarning) if comb[1] == "gi" else nullcontext(): - pk = ptc.get_biased_pk2d(ptt1, tracer2=ptt2, return_ia_bb=return_bb) + pk = ptc.get_biased_pk2d(ptt1, tracer2=ptt2, return_ia_bb=return_bb) for iz, z in enumerate(zs): a = 1./(1+z) diff --git a/pyccl/_nonlimber_FKEM.py b/pyccl/_nonlimber_FKEM.py index 12f31cc14..6556a893f 100644 --- a/pyccl/_nonlimber_FKEM.py +++ b/pyccl/_nonlimber_FKEM.py @@ -6,14 +6,13 @@ (https://jila.colorado.edu/~ajsh/FFTLog/fftlog.pdf) to compute integrals over spherical bessel functions """ -import warnings import numpy as np from . import lib, check from .pyutils import integ_types from scipy.interpolate import interp1d from pyccl.pyutils import _fftlog_transform_general import pyccl as ccl -from . import CCLWarning +from . import CCLWarning, warnings def _get_general_params(b): @@ -66,7 +65,8 @@ def _nonlimber_FKEM( warnings.warn( "p_of_k_a and p_of_k_a_lin must be of the same " "type: a str in cosmo or a Pk2D object. " - "Defaulting to Limber calculation. ", CCLWarning) + "Defaulting to Limber calculation. ", + category=CCLWarning, importance='high') return -1, np.array([]), status psp_lin = cosmo.parse_pk2d(p_of_k_a_lin, is_linear=True) diff --git a/pyccl/baryons/baccoemu_baryons.py b/pyccl/baryons/baccoemu_baryons.py index 29d024758..e83fea1dc 100644 --- a/pyccl/baryons/baccoemu_baryons.py +++ b/pyccl/baryons/baccoemu_baryons.py @@ -2,9 +2,8 @@ import numpy as np from copy import deepcopy -from warnings import warn -from .. import Pk2D +from .. import Pk2D, CCLDeprecationWarning from . import Baryons @@ -216,8 +215,9 @@ class BaccoemuBaryons(BaryonsBaccoemu): def __init__(self, *args, **kwargs): """This throws a deprecation warning on initialization.""" - warn(f"Class {self.__class__.__name__} will be deprecated. " + - f"Please use {BaryonsBaccoemu.__name__} instead.", - DeprecationWarning, stacklevel=2) + from .. import warnings + warnings.warn(f"Class {self.__class__.__name__} will be deprecated. " + + f"Please use {BaryonsBaccoemu.__name__} instead.", + CCLDeprecationWarning, stacklevel=2, + importance='low') super().__init__(*args, **kwargs) - pass diff --git a/pyccl/ccl.i b/pyccl/ccl.i index 0e34f1455..ae4f610c7 100644 --- a/pyccl/ccl.i +++ b/pyccl/ccl.i @@ -21,7 +21,7 @@ from .errors import CCLError %init %{ import_array(); // Tell CCL to not print to stdout/stderr for debugging. - ccl_set_debug_policy(CCL_DEBUG_MODE_ON); + ccl_set_debug_policy(CCL_DEBUG_MODE_OFF); %} // Automatically document arguments and output types of all functions diff --git a/pyccl/cells.py b/pyccl/cells.py index c255eb291..b86079d55 100644 --- a/pyccl/cells.py +++ b/pyccl/cells.py @@ -1,10 +1,8 @@ __all__ = ("angular_cl",) -import warnings - import numpy as np -from . import DEFAULT_POWER_SPECTRUM, CCLWarning, check, lib +from . import DEFAULT_POWER_SPECTRUM, CCLWarning, check, lib, warnings from .pyutils import integ_types from ._nonlimber_FKEM import _nonlimber_FKEM @@ -56,7 +54,7 @@ def angular_cl( the kernels are defined will be used (capped to 1E-6 Mpc if this value is zero). Users are encouraged to experiment with this parameter and ``fkem_Nchi`` to ensure the robustness of the output - :math:`C_\\ell`s. + :math:`C_\\ell` s. fkem_Nchi: Number of values of the comoving distance over which `FKEM` will interpolate the radial kernels. If ``None`` the smallest number over which the kernels are currently sampled will be used. Note that @@ -64,7 +62,7 @@ def angular_cl( ``fkem_chi_min`` and the maximum distance over which the tracers are defined. Users are encouraged to experiment with this parameter and ``fkem_chi_min`` to ensure the robustness of the output - :math:`C_\\ell`s. + :math:`C_\\ell` s. p_of_k_a_lin (:class:`~pyccl.pk2d.Pk2D`, :obj:`str` or :obj:`None`): 3D linear Power spectrum to project, for special use in PT calculations using the FKEM non-limber integration technique. @@ -84,8 +82,7 @@ def angular_cl( warnings.warn( "CCL does not properly use the hyperspherical Bessel functions " "when computing angular power spectra in non-flat cosmologies!", - category=CCLWarning, - ) + category=CCLWarning, importance='low') if limber_integration_method not in integ_types: raise ValueError( diff --git a/pyccl/errors.py b/pyccl/errors.py index f8fa620df..050998df0 100644 --- a/pyccl/errors.py +++ b/pyccl/errors.py @@ -1,6 +1,50 @@ -__all__ = ("CCLError", "CCLWarning", "CCLDeprecationWarning",) +__all__ = ("CCLError", "CCLWarning", "CCLDeprecationWarning", + "warnings", "update_warning_verbosity") -import warnings +import warnings as warnings_builtin + + +_warning_importance = {'high': 10, 'low': 1} +_verbosity_thresholds = {'none': 100, 'low': 10, 'high': 1} + + +class warnings: + _CCL_WARN_THRESHOLD = 10 # Equivalent to "low" verbosity + + def warn(*args, **kwargs): + category = kwargs.get('category') + importance = _warning_importance[kwargs.pop('importance', 'low')] + + if ((category in (CCLWarning, CCLDeprecationWarning)) and + (importance < warnings._CCL_WARN_THRESHOLD)): + return + + warnings_builtin.warn(*args, **kwargs) + + +def update_warning_verbosity(verbosity): + """ Update the level of verbosity of the CCL warnings. Available + levels are "none", "low", and "high". More warning messages will + be output for higher verbosity levels. If "none", no CCL-level + warnings will be shown. The default verbosity is "low". Note that + unless the verbosity level is "high", all C-level warnings will + be omitted. + + Args: + verbosity (str): one of ``'none'``, ``'low'`` or ``'high'``. + """ + + if not (verbosity in ['none', 'low', 'high']): + raise KeyError("`verbosity` must be one of {'none', 'low', 'high'}") + warnings._CCL_WARN_THRESHOLD = _verbosity_thresholds[verbosity] + + # Remove C-level warnings + from . import debug_mode + + if verbosity == 'high': + debug_mode(True) + else: + debug_mode(False) class CCLError(RuntimeError): @@ -40,8 +84,8 @@ def __hash__(self): @classmethod def enable(cls): - warnings.simplefilter("always") + warnings_builtin.simplefilter("always") @classmethod def disable(cls): - warnings.filterwarnings(action="ignore", category=cls) + warnings_builtin.filterwarnings(action="ignore", category=cls) diff --git a/pyccl/halos/pk_4pt.py b/pyccl/halos/pk_4pt.py index 16a01c3ed..450b8d58b 100644 --- a/pyccl/halos/pk_4pt.py +++ b/pyccl/halos/pk_4pt.py @@ -5,12 +5,10 @@ "halomod_Tk3D_SSC_linear_bias", "halomod_Tk3D_SSC", "halomod_Tk3D_cNG") -import warnings - import numpy as np import scipy -from .. import CCLWarning, Tk3D, Pk2D +from .. import CCLWarning, warnings, Tk3D, Pk2D from . import HaloProfileNFW, Profile2pt @@ -607,7 +605,8 @@ def _logged_output(*arrs, log): is_negative = [(arr <= 0).any() for arr in arrs] if any(is_negative): warnings.warn("Some values were non-positive. " - "Interpolating linearly.", CCLWarning) + "Interpolating linearly.", + category=CCLWarning, importance='high') return *arrs, False return *[np.log(arr) for arr in arrs], log diff --git a/pyccl/halos/profiles/ia.py b/pyccl/halos/profiles/ia.py index 472536a21..21abc84f0 100644 --- a/pyccl/halos/profiles/ia.py +++ b/pyccl/halos/profiles/ia.py @@ -1,7 +1,7 @@ -import warnings import pyccl import numpy as np from .hod import HaloProfileHOD +from ... import warnings __all__ = ("SatelliteShearHOD",) @@ -100,12 +100,12 @@ def __init__(self, *, mass_def, concentration, a1h=0.001, b=-2, lmax = 12 warnings.warn( 'Maximum l provided too high. Using lmax=12.', - category=pyccl.CCLWarning) + category=pyccl.CCLWarning, importance='high') elif lmax < 2: lmax = 2 warnings.warn( 'Maximum l provided too low. Using lmax=2.', - category=pyccl.CCLWarning) + category=pyccl.CCLWarning, importance='high') self.a1h = a1h self.b = b if integration_method not in ['FFTLog', diff --git a/pyccl/nl_pt/ept.py b/pyccl/nl_pt/ept.py index a50acc6a0..4b42b7e5a 100644 --- a/pyccl/nl_pt/ept.py +++ b/pyccl/nl_pt/ept.py @@ -1,11 +1,9 @@ __all__ = ("EulerianPTCalculator",) -import warnings - import numpy as np from .. import (CCLAutoRepr, CCLError, CCLWarning, Pk2D, - get_pk_spline_a, unlock_instance) + get_pk_spline_a, unlock_instance, warnings) # All valid Pk pair labels and their aliases @@ -375,7 +373,7 @@ def _get_pgi(self, trg, tri): warnings.warn( "EulerianPTCalculators assume linear galaxy bias " "when computing galaxy-IA cross-correlations.", - category=CCLWarning) + category=CCLWarning, importance='low') c1 = tri.c1(self.z_s) c2 = tri.c2(self.z_s) cd = tri.cdelta(self.z_s) diff --git a/pyccl/pk2d.py b/pyccl/pk2d.py index e24730345..b06dd3a2c 100644 --- a/pyccl/pk2d.py +++ b/pyccl/pk2d.py @@ -1,13 +1,11 @@ __all__ = ("Pk2D", "parse_pk2d", "parse_pk",) -import warnings - import numpy as np from . import ( CCLObject, DEFAULT_POWER_SPECTRUM, UnlockInstance, check, get_pk_spline_a, get_pk_spline_lk, lib, unlock_instance) -from . import CCLWarning, CCLError +from . import CCLWarning, CCLError, warnings from .pyutils import _get_spline1d_arrays, _get_spline2d_arrays @@ -375,7 +373,8 @@ def _get_binary_operator_arrays(self, other): "Operands defined over different ranges. " "The result will be interpolated and clipped to " f"{self.psp.lkmin} <= log k <= {self.psp.lkmax} and " - f"{self.psp.amin} <= a <= {self.psp.amax}.", CCLWarning) + f"{self.psp.amin} <= a <= {self.psp.amax}.", + category=CCLWarning, importance='low') pk_arr_b = other(np.exp(lk_arr_a), a_arr_a) return a_arr_a, lk_arr_a, pk_arr_a, pk_arr_b @@ -449,7 +448,8 @@ def __pow__(self, exponent): if np.any(pk_arr_a < 0) and exponent % 1 != 0: warnings.warn( "Taking a non-positive Pk2D object to a non-integer " - "power may lead to unexpected results", CCLWarning) + "power may lead to unexpected results", + category=CCLWarning, importance='high') pk_arr_new = pk_arr_a**exponent diff --git a/pyccl/tests/test_cclerror.py b/pyccl/tests/test_cclerror.py index c0b19a7b1..0e1df7475 100644 --- a/pyccl/tests/test_cclerror.py +++ b/pyccl/tests/test_cclerror.py @@ -1,4 +1,7 @@ import pyccl +import pytest +import numpy as np +import warnings def test_cclerror_repr(): @@ -62,3 +65,40 @@ def test_ccl_deprecationwarning_switch(): # switch back on pyccl.CCLDeprecationWarning.enable() + + +def test_ccl_warning_verbosity_error(): + with pytest.raises(KeyError): + pyccl.update_warning_verbosity("hihg") + + +def test_ccl_warning_verbosity(): + + # The code below will trigger an unimportant warning + # about the N(z) sampling + + # Switch to high verbosity + pyccl.update_warning_verbosity("high") + cosmo = pyccl.CosmologyVanillaLCDM() + numz = 32 + zm = 0.7 + sz = 0.01 + z = np.linspace(0, 1.5, numz) + nz = np.exp(-0.5*((z-zm)/sz)**2) + with pytest.warns(pyccl.CCLWarning): + pyccl.WeakLensingTracer(cosmo, dndz=(z, nz)) + + # Now test that no warning is triggered if back to low verbosity + pyccl.update_warning_verbosity("low") + + with warnings.catch_warnings(): + warnings.simplefilter("error") + pyccl.WeakLensingTracer(cosmo, dndz=(z, nz)) + + +def test_ccl_deprecation_warning(): + # Switch to high verbosity to catch it + pyccl.update_warning_verbosity("high") + with pytest.warns(pyccl.CCLDeprecationWarning): + pyccl.baryons.BaccoemuBaryons() + pyccl.update_warning_verbosity("low") diff --git a/pyccl/tests/test_cosmology_parameters.py b/pyccl/tests/test_cosmology_parameters.py index f24fca32e..6c1a77b56 100644 --- a/pyccl/tests/test_cosmology_parameters.py +++ b/pyccl/tests/test_cosmology_parameters.py @@ -2,7 +2,6 @@ import numpy as np import pytest import pyccl as ccl -# import warnings # TODO: Uncomment for CCLv3. def test_parameters_lcdmDefaultParams(): diff --git a/pyccl/tests/test_ept_power.py b/pyccl/tests/test_ept_power.py index 9f4a95224..53b0741aa 100644 --- a/pyccl/tests/test_ept_power.py +++ b/pyccl/tests/test_ept_power.py @@ -43,8 +43,10 @@ def test_ept_get_pk2d_smoke(tr1, tr2, bb, sub_lowk): sub_lowk=sub_lowk, cosmo=COSMO) will_warn = set([tr1, tr2]) == set(["TG", "TI"]) + ccl.update_warning_verbosity('high') with pytest.warns(ccl.CCLWarning) if will_warn else nullcontext(): pk = ptc.get_biased_pk2d(TRS[tr1], tracer2=t2, return_ia_bb=bb) + ccl.update_warning_verbosity('low') assert isinstance(pk, ccl.Pk2D) @@ -118,8 +120,10 @@ def get_tr(tn): is_nl = tn1 in ["b2", "bs", "bk2", "b3nl"] is_g = tn2 in ["c1", "c2", "cdelta"] + ccl.update_warning_verbosity('high') with pytest.warns(ccl.CCLWarning) if is_nl and is_g else nullcontext(): pk2 = ptc.get_biased_pk2d(t1, tracer2=t2) + ccl.update_warning_verbosity('low') if pk1 is None: assert pk2(0.5, 1.0, cosmo=COSMO) == 0.0 else: @@ -237,11 +241,13 @@ def test_ept_calculator_raises(): ptc.get_pk2d_template('b1:b3') # Warning when computing IA-gal correlation + ccl.update_warning_verbosity('high') with pytest.warns(ccl.CCLWarning): ptc = ccl.nl_pt.EulerianPTCalculator(with_NC=True, with_IA=True, cosmo=COSMO) tg = ccl.nl_pt.PTNumberCountsTracer(b1=1.0, b2=1.0) ptc.get_biased_pk2d(tg, tracer2=TRS['TI']) + ccl.update_warning_verbosity('low') def test_ept_template_swap(): diff --git a/pyccl/tests/test_pk2d.py b/pyccl/tests/test_pk2d.py index 82c1926f6..3fb84b67e 100644 --- a/pyccl/tests/test_pk2d.py +++ b/pyccl/tests/test_pk2d.py @@ -339,8 +339,10 @@ def test_pk2d_add(): # This raises a warning because the power spectra are not defined on the # same support + ccl.update_warning_verbosity('high') with pytest.warns(CCLWarning): pk2d_f = pk2d_e + pk2d_a + ccl.update_warning_verbosity('low') xarr_f, yarr_f, zarr_f = pk2d_f.get_spline_arrays() @@ -370,8 +372,10 @@ def test_pk2d_mul_pow(): # This raises a warning because the power spectrum is non-negative and the # power is non-integer + ccl.update_warning_verbosity('high') with pytest.warns(CCLWarning): pk2d_b**0.5 + ccl.update_warning_verbosity('low') pk2d_g = pk2d_a * pk2d_b pk2d_h = 2*pk2d_a diff --git a/pyccl/tests/test_tkk1h.py b/pyccl/tests/test_tkk1h.py index ae69afa96..318f3e9e5 100644 --- a/pyccl/tests/test_tkk1h.py +++ b/pyccl/tests/test_tkk1h.py @@ -106,7 +106,9 @@ def test_tkk1h_warns(): # Negative profile in logspace Pneg = ccl.halos.HaloProfilePressureGNFW(mass_def=M200, P0=-1) + ccl.update_warning_verbosity('high') with pytest.warns(ccl.CCLWarning): ccl.halos.halomod_Tk3D_1h( COSMO, hmc, P3, prof2=Pneg, prof3=P3, prof4=P3, lk_arr=np.log(KK), a_arr=a_arr, use_log=True) + ccl.update_warning_verbosity('low') diff --git a/pyccl/tests/test_tracers.py b/pyccl/tests/test_tracers.py index bb467ff81..2341575b9 100644 --- a/pyccl/tests/test_tracers.py +++ b/pyccl/tests/test_tracers.py @@ -403,8 +403,10 @@ def test_tracer_n_sample_warn(): z = np.linspace(0., 1., 50) n = dndz(z) + ccl.update_warning_verbosity('high') with pytest.warns(CCLWarning): _ = ccl.WeakLensingTracer(COSMO, dndz=(z, n)) + ccl.update_warning_verbosity('low') def test_tracer_bool(): diff --git a/pyccl/tracers.py b/pyccl/tracers.py index ec0372a63..251abf949 100644 --- a/pyccl/tracers.py +++ b/pyccl/tracers.py @@ -26,13 +26,11 @@ documentation of the base :class:`Tracer` class is a good place to start. """ -import warnings - import numpy as np from . import ccllib as lib from .pyutils import check -from .errors import CCLWarning +from .errors import CCLWarning, warnings from ._core.parameters import physical_constants from ._core import CCLObject, UnlockInstance, unlock_instance from .pyutils import (_check_array_params, NoneArr, _vectorize_fn6, @@ -152,7 +150,8 @@ def get_lensing_kernel(cosmo, *, dndz, mag_bias=None, n_chi=None): f"the number of samples in the lensing kernel ({n_chi}). Consider " "disabling spline integration for the lensing kernel by setting " "pyccl.gsl_params.LENSING_KERNEL_SPLINE_INTEGRATION = False " - "before instantiating the Cosmology passed.", category=CCLWarning) + "before instantiating the Cosmology passed.", + category=CCLWarning, importance='low') # Compute array of chis status = 0 diff --git a/readthedocs/api/pyccl.halos.hmfunc.nishimichi19.rst b/readthedocs/api/pyccl.halos.hmfunc.nishimichi19.rst new file mode 100644 index 000000000..c607369d0 --- /dev/null +++ b/readthedocs/api/pyccl.halos.hmfunc.nishimichi19.rst @@ -0,0 +1,7 @@ +pyccl.halos.hmfunc.nishimichi19 module +====================================== + +.. automodule:: pyccl.halos.hmfunc.nishimichi19 + :members: + :undoc-members: + :show-inheritance: diff --git a/readthedocs/api/pyccl.halos.hmfunc.rst b/readthedocs/api/pyccl.halos.hmfunc.rst index f62249226..189091634 100644 --- a/readthedocs/api/pyccl.halos.hmfunc.rst +++ b/readthedocs/api/pyccl.halos.hmfunc.rst @@ -12,6 +12,7 @@ Submodules pyccl.halos.hmfunc.bocquet20 pyccl.halos.hmfunc.despali16 pyccl.halos.hmfunc.jenkins01 + pyccl.halos.hmfunc.nishimichi19 pyccl.halos.hmfunc.press74 pyccl.halos.hmfunc.sheth99 pyccl.halos.hmfunc.tinker08 diff --git a/src/ccl_error.c b/src/ccl_error.c index 4ffbb0552..b0354654e 100644 --- a/src/ccl_error.c +++ b/src/ccl_error.c @@ -9,7 +9,7 @@ // Debug mode policy: whether to print error messages as they are raised. // Defualt is ON. -static CCLDebugModePolicy _ccl_debug_mode_policy = CCL_DEBUG_MODE_ON; +static CCLDebugModePolicy _ccl_debug_mode_policy = CCL_DEBUG_MODE_OFF; // Set debug mode policy void ccl_set_debug_policy(CCLDebugModePolicy debug_policy) {