pyccl 3.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyccl/.gitignore +1 -0
- pyccl/CMakeLists.txt +42 -0
- pyccl/__init__.py +47 -0
- pyccl/_ccllib.so +0 -0
- pyccl/_core/__init__.py +4 -0
- pyccl/_core/caching.py +303 -0
- pyccl/_core/deprecations.py +73 -0
- pyccl/_core/parameters/__init__.py +3 -0
- pyccl/_core/parameters/cosmology_params.py +21 -0
- pyccl/_core/parameters/fftlog_params.py +100 -0
- pyccl/_core/parameters/parameters_base.py +141 -0
- pyccl/_core/repr_.py +385 -0
- pyccl/_core/schema.py +376 -0
- pyccl/background.py +516 -0
- pyccl/baryons/__init__.py +4 -0
- pyccl/baryons/baccoemu_baryons.py +223 -0
- pyccl/baryons/baryons_base.py +41 -0
- pyccl/baryons/schneider15.py +96 -0
- pyccl/baryons/vandaalen19.py +111 -0
- pyccl/boltzmann.py +499 -0
- pyccl/ccl.i +61 -0
- pyccl/ccl_background.i +131 -0
- pyccl/ccl_cls.i +114 -0
- pyccl/ccl_core.i +48 -0
- pyccl/ccl_correlation.i +100 -0
- pyccl/ccl_covs.i +96 -0
- pyccl/ccl_f1d.i +54 -0
- pyccl/ccl_fftlog.i +109 -0
- pyccl/ccl_mass_conversion.i +32 -0
- pyccl/ccl_musigma.i +55 -0
- pyccl/ccl_neutrinos.i +30 -0
- pyccl/ccl_pk2d.i +65 -0
- pyccl/ccl_power.i +64 -0
- pyccl/ccl_sigM.i +41 -0
- pyccl/ccl_tk3d.i +58 -0
- pyccl/ccl_tracers.i +244 -0
- pyccl/ccl_utils.i +183 -0
- pyccl/ccllib.py +1788 -0
- pyccl/cells.py +175 -0
- pyccl/correlations.py +363 -0
- pyccl/cosmology.py +1001 -0
- pyccl/covariances.py +378 -0
- pyccl/emulators/__init__.py +4 -0
- pyccl/emulators/baccoemu_linear_pk.py +119 -0
- pyccl/emulators/baccoemu_nonlinear_pk.py +121 -0
- pyccl/emulators/cosmicemu_pk.py +245 -0
- pyccl/emulators/data/CosmicEmu_MTII_2017_Pcb.npz +0 -0
- pyccl/emulators/data/CosmicEmu_MTII_2017_Ptot.npz +0 -0
- pyccl/emulators/data/CosmicEmu_MTIV_2022_Pcb.npz +0 -0
- pyccl/emulators/data/CosmicEmu_MTIV_2022_Ptot.npz +0 -0
- pyccl/emulators/emu_base.py +58 -0
- pyccl/errors.py +91 -0
- pyccl/halos/__init__.py +11 -0
- pyccl/halos/concentration/__init__.py +8 -0
- pyccl/halos/concentration/bhattacharya13.py +37 -0
- pyccl/halos/concentration/constant.py +27 -0
- pyccl/halos/concentration/diemer15.py +52 -0
- pyccl/halos/concentration/duffy08.py +39 -0
- pyccl/halos/concentration/ishiyama21.py +97 -0
- pyccl/halos/concentration/klypin11.py +25 -0
- pyccl/halos/concentration/prada12.py +54 -0
- pyccl/halos/halo_model.py +444 -0
- pyccl/halos/halo_model_base.py +291 -0
- pyccl/halos/hbias/__init__.py +5 -0
- pyccl/halos/hbias/bhattacharya11.py +38 -0
- pyccl/halos/hbias/sheth01.py +40 -0
- pyccl/halos/hbias/sheth99.py +48 -0
- pyccl/halos/hbias/tinker10.py +47 -0
- pyccl/halos/hmfunc/__init__.py +12 -0
- pyccl/halos/hmfunc/angulo12.py +37 -0
- pyccl/halos/hmfunc/bocquet16.py +100 -0
- pyccl/halos/hmfunc/bocquet20.py +79 -0
- pyccl/halos/hmfunc/despali16.py +57 -0
- pyccl/halos/hmfunc/jenkins01.py +35 -0
- pyccl/halos/hmfunc/nishimichi19.py +96 -0
- pyccl/halos/hmfunc/press74.py +33 -0
- pyccl/halos/hmfunc/sheth99.py +51 -0
- pyccl/halos/hmfunc/tinker08.py +55 -0
- pyccl/halos/hmfunc/tinker10.py +86 -0
- pyccl/halos/hmfunc/watson13.py +66 -0
- pyccl/halos/massdef.py +368 -0
- pyccl/halos/pk_1pt.py +75 -0
- pyccl/halos/pk_2pt.py +232 -0
- pyccl/halos/pk_4pt.py +1660 -0
- pyccl/halos/profiles/__init__.py +8 -0
- pyccl/halos/profiles/cib_shang12.py +276 -0
- pyccl/halos/profiles/einasto.py +153 -0
- pyccl/halos/profiles/hernquist.py +215 -0
- pyccl/halos/profiles/hod.py +403 -0
- pyccl/halos/profiles/ia.py +439 -0
- pyccl/halos/profiles/nfw.py +206 -0
- pyccl/halos/profiles/pressure_gnfw.py +245 -0
- pyccl/halos/profiles/profile_base.py +521 -0
- pyccl/halos/profiles_2pt.py +239 -0
- pyccl/modified_gravity/__init__.py +2 -0
- pyccl/modified_gravity/modified_gravity_base.py +8 -0
- pyccl/modified_gravity/mu_Sigma.py +47 -0
- pyccl/neutrinos.py +91 -0
- pyccl/nl_pt/__init__.py +4 -0
- pyccl/nl_pt/bacco_lbias.py +491 -0
- pyccl/nl_pt/ept.py +696 -0
- pyccl/nl_pt/lpt.py +485 -0
- pyccl/nl_pt/tracers.py +242 -0
- pyccl/nonlimber/__init__.py +1 -0
- pyccl/nonlimber/_nonlimber_FKEM.py +472 -0
- pyccl/numpy.i +2970 -0
- pyccl/pk2d.py +568 -0
- pyccl/power.py +208 -0
- pyccl/pyutils.py +760 -0
- pyccl/tests/__init__.py +0 -0
- pyccl/tests/conftest.py +23 -0
- pyccl/tests/test__caching.py +168 -0
- pyccl/tests/test_bacco_lbias_power.py +298 -0
- pyccl/tests/test_baccoemu.py +162 -0
- pyccl/tests/test_background.py +255 -0
- pyccl/tests/test_baryons.py +67 -0
- pyccl/tests/test_baryons_vd19.py +66 -0
- pyccl/tests/test_cclerror.py +104 -0
- pyccl/tests/test_cclobject.py +168 -0
- pyccl/tests/test_cells.py +274 -0
- pyccl/tests/test_concentration.py +95 -0
- pyccl/tests/test_correlations.py +136 -0
- pyccl/tests/test_cosmicemu.py +36 -0
- pyccl/tests/test_cosmology.py +313 -0
- pyccl/tests/test_cosmology_parameters.py +343 -0
- pyccl/tests/test_covariances.py +173 -0
- pyccl/tests/test_ept_power.py +289 -0
- pyccl/tests/test_fftlog.py +96 -0
- pyccl/tests/test_gsl_splines.py +34 -0
- pyccl/tests/test_halofit_highz.py +54 -0
- pyccl/tests/test_halomodel.py +52 -0
- pyccl/tests/test_hashing.py +34 -0
- pyccl/tests/test_hbias.py +55 -0
- pyccl/tests/test_hmcalculator_integrals.py +99 -0
- pyccl/tests/test_hmcalculator_number_counts.py +165 -0
- pyccl/tests/test_hmfunc.py +244 -0
- pyccl/tests/test_lpt_power.py +171 -0
- pyccl/tests/test_m2r_sM.py +31 -0
- pyccl/tests/test_massdef.py +122 -0
- pyccl/tests/test_massfunction.py +47 -0
- pyccl/tests/test_mg.py +128 -0
- pyccl/tests/test_neutrinos.py +20 -0
- pyccl/tests/test_nonlin_camb_power.py +60 -0
- pyccl/tests/test_pk2d.py +481 -0
- pyccl/tests/test_pkhm.py +298 -0
- pyccl/tests/test_power.py +512 -0
- pyccl/tests/test_power_mu_sigma_sigma8norm.py +96 -0
- pyccl/tests/test_profiles.py +741 -0
- pyccl/tests/test_pt_tracers.py +58 -0
- pyccl/tests/test_pyutils.py +11 -0
- pyccl/tests/test_resampling.py +65 -0
- pyccl/tests/test_spline_integ.py +67 -0
- pyccl/tests/test_swig_interface.py +138 -0
- pyccl/tests/test_tk3d.py +233 -0
- pyccl/tests/test_tkk1h.py +114 -0
- pyccl/tests/test_tkk2h.py +326 -0
- pyccl/tests/test_tkk3h.py +211 -0
- pyccl/tests/test_tkk4h.py +155 -0
- pyccl/tests/test_tkk_separable_growth.py +207 -0
- pyccl/tests/test_tkkcNG.py +108 -0
- pyccl/tests/test_tkkssc.py +236 -0
- pyccl/tests/test_tracers.py +502 -0
- pyccl/tests/test_yaml.py +79 -0
- pyccl/tk3d.py +257 -0
- pyccl/tracers.py +1120 -0
- pyccl-3.3.0.dist-info/METADATA +160 -0
- pyccl-3.3.0.dist-info/RECORD +171 -0
- pyccl-3.3.0.dist-info/WHEEL +5 -0
- pyccl-3.3.0.dist-info/licenses/LICENSE +27 -0
- pyccl-3.3.0.dist-info/licenses/LICENSE_COSMICEMU +10 -0
- pyccl-3.3.0.dist-info/top_level.txt +1 -0
pyccl/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
_version.py
|
pyccl/CMakeLists.txt
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Builds the python module
|
|
3
|
+
#
|
|
4
|
+
include(BuildSWIG)
|
|
5
|
+
include(UseSWIG)
|
|
6
|
+
#set (UseSWIG_TARGET_NAME_PREFERENCE STANDARD)
|
|
7
|
+
|
|
8
|
+
find_package(PythonLibsNew ${PYTHON_VERSION})
|
|
9
|
+
find_package(NumPy)
|
|
10
|
+
include_directories(BEFORE ${PYTHON_INCLUDE_DIRS} ${NUMPY_INCLUDE_DIRS})
|
|
11
|
+
|
|
12
|
+
# We also build a static library only for linking the python module
|
|
13
|
+
add_library(ccl_static STATIC $<TARGET_OBJECTS:objlib>)
|
|
14
|
+
target_link_libraries(ccl_static ${GSL_LIBRARIES} ${CLASS_LIBRARIES} ${FFTW_LIBRARIES} m)
|
|
15
|
+
add_dependencies(ccl_static ccl)
|
|
16
|
+
|
|
17
|
+
# Adds these extra depencies before building SWIG interface, to ensure that SWIG
|
|
18
|
+
# will be built first if need, same goes for GSL (through ccl_static)
|
|
19
|
+
set(SWIG_MODULE_ccllib_EXTRA_DEPS ccl_static)
|
|
20
|
+
if(NOT SWIG_FOUND)
|
|
21
|
+
set(SWIG_MODULE_ccllib_EXTRA_DEPS ${SWIG_MODULE_ccllib_EXTRA_DEPS} SWIG)
|
|
22
|
+
endif()
|
|
23
|
+
|
|
24
|
+
# Builds swig python module in place
|
|
25
|
+
if(${CMAKE_VERSION} VERSION_LESS "3.8.0")
|
|
26
|
+
swig_add_module(ccllib python ccl.i)
|
|
27
|
+
else()
|
|
28
|
+
swig_add_library(ccllib TYPE SHARED LANGUAGE python SOURCES ccl.i)
|
|
29
|
+
endif()
|
|
30
|
+
swig_link_libraries(ccllib ccl_static)
|
|
31
|
+
|
|
32
|
+
if(APPLE)
|
|
33
|
+
# SWIG>=4.4 triggers int-conversion warning/error while calling numpy's import_array()
|
|
34
|
+
# GCC seems to be raising warnings but clang raises an error, instead.
|
|
35
|
+
# We make clang to treat them as warnings with next line.
|
|
36
|
+
target_compile_options(${SWIG_MODULE_ccllib_REAL_NAME} PRIVATE "-Wno-error=int-conversion")
|
|
37
|
+
# Unpleasant subtelty for linking on osx
|
|
38
|
+
set_target_properties(${SWIG_MODULE_ccllib_REAL_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
|
|
39
|
+
else(APPLE)
|
|
40
|
+
swig_link_libraries(ccllib ${PYTHON_LIBRARIES})
|
|
41
|
+
endif()
|
|
42
|
+
set_target_properties(${SWIG_MODULE_ccllib_REAL_NAME} PROPERTIES SUFFIX .so)
|
pyccl/__init__.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# flake8: noqa E402
|
|
2
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
3
|
+
try:
|
|
4
|
+
__version__ = version(__name__)
|
|
5
|
+
except PackageNotFoundError:
|
|
6
|
+
pass # not installed
|
|
7
|
+
del version, PackageNotFoundError
|
|
8
|
+
|
|
9
|
+
# Set the environment variable for default config path
|
|
10
|
+
from os import environ, path
|
|
11
|
+
if environ.get("CLASS_PARAM_DIR") is None:
|
|
12
|
+
environ["CLASS_PARAM_DIR"] = path.dirname(path.abspath(__file__))
|
|
13
|
+
del environ, path
|
|
14
|
+
|
|
15
|
+
# Patch for deprecated alias in Numpy >= 1.20.0 (used in ISiTGR & FAST-PT).
|
|
16
|
+
# Deprecation cycle starts in Numpy 1.20 and ends in Numpy 1.24.
|
|
17
|
+
from packaging.version import parse
|
|
18
|
+
import numpy
|
|
19
|
+
numpy.int = int if parse(numpy.__version__) >= parse("1.20.0") else numpy.int
|
|
20
|
+
del parse, numpy
|
|
21
|
+
|
|
22
|
+
from . import ccllib as lib
|
|
23
|
+
from .errors import *
|
|
24
|
+
from ._core import *
|
|
25
|
+
from .pyutils import *
|
|
26
|
+
|
|
27
|
+
from .background import *
|
|
28
|
+
from .power import *
|
|
29
|
+
|
|
30
|
+
from .tracers import *
|
|
31
|
+
from .cells import *
|
|
32
|
+
from .correlations import *
|
|
33
|
+
from .covariances import *
|
|
34
|
+
|
|
35
|
+
from .pk2d import *
|
|
36
|
+
from .tk3d import *
|
|
37
|
+
|
|
38
|
+
from .boltzmann import *
|
|
39
|
+
from .baryons import *
|
|
40
|
+
from .neutrinos import *
|
|
41
|
+
from .emulators import *
|
|
42
|
+
from .nonlimber import *
|
|
43
|
+
|
|
44
|
+
from . import halos
|
|
45
|
+
from . import nl_pt
|
|
46
|
+
|
|
47
|
+
from .cosmology import *
|
pyccl/_ccllib.so
ADDED
|
Binary file
|
pyccl/_core/__init__.py
ADDED
pyccl/_core/caching.py
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
__all__ = ("hash_", "Caching", "cache", "CacheInfo", "CachedObject",)
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import functools
|
|
5
|
+
from collections import OrderedDict
|
|
6
|
+
from inspect import signature
|
|
7
|
+
from _thread import RLock
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _to_hashable(obj):
|
|
13
|
+
"""Make unhashable objects hashable in a consistent manner."""
|
|
14
|
+
|
|
15
|
+
if isinstance(obj, (int, float, str)):
|
|
16
|
+
# Strings and Numbers are hashed directly.
|
|
17
|
+
return obj
|
|
18
|
+
|
|
19
|
+
elif hasattr(obj, "__iter__"):
|
|
20
|
+
# Encapsulate all the iterables to quickly discard as needed.
|
|
21
|
+
|
|
22
|
+
if isinstance(obj, np.ndarray):
|
|
23
|
+
# Numpy arrays: Convert the data buffer to a byte string.
|
|
24
|
+
return obj.tobytes()
|
|
25
|
+
|
|
26
|
+
elif isinstance(obj, dict):
|
|
27
|
+
# Dictionaries: Build a tuple from key-value pairs,
|
|
28
|
+
# where all values are converted to hashables.
|
|
29
|
+
out = {key: _to_hashable(value) for key, value in obj.items()}
|
|
30
|
+
# Sort unordered dictionaries for hash consistency.
|
|
31
|
+
if isinstance(obj, OrderedDict):
|
|
32
|
+
return tuple(out.items())
|
|
33
|
+
return tuple(sorted(out.items()))
|
|
34
|
+
|
|
35
|
+
else:
|
|
36
|
+
# Iterables: Build a tuple from values converted to hashables.
|
|
37
|
+
out = [_to_hashable(item) for item in obj]
|
|
38
|
+
return tuple(out)
|
|
39
|
+
|
|
40
|
+
elif hasattr(obj, "__hash__"):
|
|
41
|
+
# Hashables: Just return the object.
|
|
42
|
+
return obj
|
|
43
|
+
|
|
44
|
+
# NotImplemented: Can't hash safely, so raise TypeError.
|
|
45
|
+
# Note: This will never be triggered since `type` has a repr slot wrapper.
|
|
46
|
+
raise TypeError(f"Hashing for {type(obj)} not implemented.")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def hash_(obj):
|
|
50
|
+
"""Generic hash method, which changes between processes."""
|
|
51
|
+
digest = hash(repr(_to_hashable(obj))) + sys.maxsize + 1
|
|
52
|
+
return digest
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class _CachingMeta(type):
|
|
56
|
+
"""Implement ``property`` to a ``classmethod`` for ``Caching``."""
|
|
57
|
+
# NOTE: Only in 3.8 < py < 3.11 can `classmethod` wrap `property`.
|
|
58
|
+
# https://docs.python.org/3.11/library/functions.html#classmethod
|
|
59
|
+
@property
|
|
60
|
+
def maxsize(cls):
|
|
61
|
+
return cls._maxsize
|
|
62
|
+
|
|
63
|
+
@maxsize.setter
|
|
64
|
+
def maxsize(cls, value):
|
|
65
|
+
if value < 0:
|
|
66
|
+
raise ValueError(
|
|
67
|
+
"`maxsize` should be larger than zero. "
|
|
68
|
+
"To disable caching, use `Caching.disable()`.")
|
|
69
|
+
cls._maxsize = value
|
|
70
|
+
for func in cls._cached_functions:
|
|
71
|
+
func.cache_info.maxsize = value
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def policy(cls):
|
|
75
|
+
return cls._policy
|
|
76
|
+
|
|
77
|
+
@policy.setter
|
|
78
|
+
def policy(cls, value):
|
|
79
|
+
if value not in cls._policies:
|
|
80
|
+
raise ValueError("Cache retention policy not recognized.")
|
|
81
|
+
if value == "lfu" != cls._policy:
|
|
82
|
+
# Reset counter if we change policy to lfu
|
|
83
|
+
# otherwise new objects are prone to being discarded immediately.
|
|
84
|
+
# Now, the counter is not just used for stats,
|
|
85
|
+
# it is part of the retention policy.
|
|
86
|
+
for func in cls._cached_functions:
|
|
87
|
+
for item in func.cache_info._caches.values():
|
|
88
|
+
item.reset()
|
|
89
|
+
cls._policy = value
|
|
90
|
+
for func in cls._cached_functions:
|
|
91
|
+
func.cache_info.policy = value
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Caching(metaclass=_CachingMeta):
|
|
95
|
+
"""Infrastructure to hold cached objects.
|
|
96
|
+
|
|
97
|
+
Caching is used for pre-computed objects that are expensive to compute.
|
|
98
|
+
|
|
99
|
+
Attributes:
|
|
100
|
+
maxsize (``int``):
|
|
101
|
+
Maximum number of caches to store. If the dictionary is full, new
|
|
102
|
+
caches are assigned according to the set cache retention policy.
|
|
103
|
+
policy (``'fifo'``, ``'lru'``, ``'lfu'``):
|
|
104
|
+
Cache retention policy.
|
|
105
|
+
"""
|
|
106
|
+
_enabled: bool = False
|
|
107
|
+
_policies: list = ['fifo', 'lru', 'lfu']
|
|
108
|
+
_default_maxsize: int = 128 # class default maxsize
|
|
109
|
+
_default_policy: str = 'lru' # class default policy
|
|
110
|
+
_maxsize = _default_maxsize # user-defined maxsize
|
|
111
|
+
_policy = _default_policy # user-defined policy
|
|
112
|
+
_cached_functions: list = []
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def _get_key(cls, func, *args, **kwargs):
|
|
116
|
+
"""Calculate the hex hash from arguments and keyword arguments."""
|
|
117
|
+
# get a dictionary of default parameters
|
|
118
|
+
params = func.cache_info._signature.parameters
|
|
119
|
+
# get a dictionary of the passed parameters
|
|
120
|
+
passed = {**dict(zip(params, args)), **kwargs}
|
|
121
|
+
# discard the values equal to the default
|
|
122
|
+
defaults = {param: value.default for param, value in params.items()}
|
|
123
|
+
return hex(hash_({**defaults, **passed}))
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def _get(cls, dic, key, policy):
|
|
127
|
+
"""Get the cached object container
|
|
128
|
+
under the implemented caching policy.
|
|
129
|
+
"""
|
|
130
|
+
obj = dic[key]
|
|
131
|
+
if policy == "lru":
|
|
132
|
+
dic.move_to_end(key)
|
|
133
|
+
# update stats
|
|
134
|
+
obj.increment()
|
|
135
|
+
return obj
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def _pop(cls, dic, policy):
|
|
139
|
+
"""Remove one cached item as per the implemented caching policy."""
|
|
140
|
+
if policy == "lfu":
|
|
141
|
+
keys = list(dic)
|
|
142
|
+
idx = np.argmin([item.counter for item in dic.values()])
|
|
143
|
+
dic.move_to_end(keys[idx], last=False)
|
|
144
|
+
dic.popitem(last=False)
|
|
145
|
+
|
|
146
|
+
@classmethod
|
|
147
|
+
def _decorator(cls, func, maxsize, policy):
|
|
148
|
+
# assign caching attributes to decorated function
|
|
149
|
+
func.cache_info = CacheInfo(func, maxsize=maxsize, policy=policy)
|
|
150
|
+
func.clear_cache = func.cache_info._clear_cache
|
|
151
|
+
cls._cached_functions.append(func)
|
|
152
|
+
|
|
153
|
+
@functools.wraps(func)
|
|
154
|
+
def wrapper(*args, **kwargs):
|
|
155
|
+
if not cls._enabled:
|
|
156
|
+
return func(*args, **kwargs)
|
|
157
|
+
|
|
158
|
+
key = cls._get_key(func, *args, **kwargs)
|
|
159
|
+
# shorthand access
|
|
160
|
+
caches = func.cache_info._caches
|
|
161
|
+
maxsize = func.cache_info.maxsize
|
|
162
|
+
policy = func.cache_info.policy
|
|
163
|
+
|
|
164
|
+
with RLock():
|
|
165
|
+
if key in caches:
|
|
166
|
+
# output has been cached; update stats and return it
|
|
167
|
+
out = cls._get(caches, key, policy)
|
|
168
|
+
func.cache_info.hits += 1
|
|
169
|
+
return out.item
|
|
170
|
+
|
|
171
|
+
with RLock():
|
|
172
|
+
while len(caches) >= maxsize:
|
|
173
|
+
# output not cached and no space available, so remove
|
|
174
|
+
# items as per the caching policy until there is space
|
|
175
|
+
cls._pop(caches, policy)
|
|
176
|
+
|
|
177
|
+
# cache new entry and update stats
|
|
178
|
+
out = CachedObject(func(*args, **kwargs))
|
|
179
|
+
caches[key] = out
|
|
180
|
+
func.cache_info.misses += 1
|
|
181
|
+
return out.item
|
|
182
|
+
|
|
183
|
+
return wrapper
|
|
184
|
+
|
|
185
|
+
@classmethod
|
|
186
|
+
def cache(cls, func=None, *, maxsize=_maxsize, policy=_policy):
|
|
187
|
+
"""Cache the output of the decorated function, using the input
|
|
188
|
+
arguments as a proxy to build a hash key.
|
|
189
|
+
|
|
190
|
+
Arguments:
|
|
191
|
+
func (``function``):
|
|
192
|
+
Function to be decorated.
|
|
193
|
+
maxsize (``int``):
|
|
194
|
+
Maximum cache size for the decorated function.
|
|
195
|
+
policy (``'fifo'``, ``'lru'``, ``'lfu'``):
|
|
196
|
+
Cache retention policy. When the storage reaches maxsize
|
|
197
|
+
decide which cached object will be deleted. Default is 'lru'.\n
|
|
198
|
+
'fifo': first-in-first-out,\n
|
|
199
|
+
'lru': least-recently-used,\n
|
|
200
|
+
'lfu': least-frequently-used.
|
|
201
|
+
"""
|
|
202
|
+
if maxsize < 0:
|
|
203
|
+
raise ValueError(
|
|
204
|
+
"`maxsize` should be larger than zero. "
|
|
205
|
+
"To disable caching, use `Caching.disable()`.")
|
|
206
|
+
if policy not in cls._policies:
|
|
207
|
+
raise ValueError("Cache retention policy not recognized.")
|
|
208
|
+
|
|
209
|
+
if func is None:
|
|
210
|
+
# `@cache` with parentheses
|
|
211
|
+
return functools.partial(
|
|
212
|
+
cls._decorator, maxsize=maxsize, policy=policy)
|
|
213
|
+
# `@cache()` without parentheses
|
|
214
|
+
return cls._decorator(func, maxsize=maxsize, policy=policy)
|
|
215
|
+
|
|
216
|
+
@classmethod
|
|
217
|
+
def enable(cls):
|
|
218
|
+
cls._enabled = True
|
|
219
|
+
|
|
220
|
+
@classmethod
|
|
221
|
+
def disable(cls):
|
|
222
|
+
cls._enabled = False
|
|
223
|
+
|
|
224
|
+
@classmethod
|
|
225
|
+
def reset(cls):
|
|
226
|
+
cls.maxsize = cls._default_maxsize
|
|
227
|
+
cls.policy = cls._default_policy
|
|
228
|
+
|
|
229
|
+
@classmethod
|
|
230
|
+
def clear_cache(cls):
|
|
231
|
+
[func.clear_cache() for func in cls._cached_functions]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
cache = Caching.cache
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class CacheInfo:
|
|
238
|
+
"""Cache info container.
|
|
239
|
+
Assigned to cached function as ``function.cache_info``.
|
|
240
|
+
|
|
241
|
+
Parameters:
|
|
242
|
+
func (``function``):
|
|
243
|
+
Function in which an instance of this class will be assigned.
|
|
244
|
+
maxsize (``Caching.maxsize``):
|
|
245
|
+
Maximum number of caches to store.
|
|
246
|
+
policy (``Caching.policy``):
|
|
247
|
+
Cache retention policy.
|
|
248
|
+
|
|
249
|
+
.. note:: To assist in deciding an optimal ``maxsize`` and ``policy``,
|
|
250
|
+
instances of this class contain the following attributes:
|
|
251
|
+
- ``hits``: number of times the function has been bypassed.
|
|
252
|
+
- ``misses``: number of times the function has computed
|
|
253
|
+
something.
|
|
254
|
+
- ``current_size``: current size of the cache dictionary.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
def __init__(self, func, maxsize=Caching.maxsize, policy=Caching.policy):
|
|
258
|
+
# we store the signature of the function on import
|
|
259
|
+
# as it is the most expensive operation (~30x slower)
|
|
260
|
+
self._signature = signature(func)
|
|
261
|
+
self._caches = OrderedDict()
|
|
262
|
+
self.maxsize = maxsize
|
|
263
|
+
self.policy = policy
|
|
264
|
+
self.hits = self.misses = 0
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def current_size(self):
|
|
268
|
+
return len(self._caches)
|
|
269
|
+
|
|
270
|
+
def __repr__(self):
|
|
271
|
+
s = f"<{self.__class__.__name__}>"
|
|
272
|
+
for par, val in self.__dict__.items():
|
|
273
|
+
if not par.startswith("_"):
|
|
274
|
+
s += f"\n\t {par} = {val!r}"
|
|
275
|
+
s += f"\n\t current_size = {self.current_size!r}"
|
|
276
|
+
return s
|
|
277
|
+
|
|
278
|
+
def _clear_cache(self):
|
|
279
|
+
self._caches = OrderedDict()
|
|
280
|
+
self.hits = self.misses = 0
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class CachedObject:
|
|
284
|
+
"""A cached object container.
|
|
285
|
+
|
|
286
|
+
Attributes:
|
|
287
|
+
counter (``int``):
|
|
288
|
+
Number of times the cached item has been retrieved.
|
|
289
|
+
"""
|
|
290
|
+
counter: int = 0
|
|
291
|
+
|
|
292
|
+
def __init__(self, obj):
|
|
293
|
+
self.item = obj
|
|
294
|
+
|
|
295
|
+
def __repr__(self):
|
|
296
|
+
s = f"CachedObject(counter={self.counter})"
|
|
297
|
+
return s
|
|
298
|
+
|
|
299
|
+
def increment(self):
|
|
300
|
+
self.counter += 1
|
|
301
|
+
|
|
302
|
+
def reset(self):
|
|
303
|
+
self.counter = 0
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
__all__ = ("deprecated", "deprecate_attr",)
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
from .. import CCLDeprecationWarning
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def deprecated(new_function=None):
|
|
10
|
+
"""This is a decorator which can be used to mark functions
|
|
11
|
+
as deprecated. It will result in a warning being emitted
|
|
12
|
+
when the function is used. If there is a replacement function,
|
|
13
|
+
pass it as `new_function`.
|
|
14
|
+
"""
|
|
15
|
+
def decorator(func):
|
|
16
|
+
@functools.wraps(func)
|
|
17
|
+
def wrapper(*args, **kwargs):
|
|
18
|
+
s = f"The function {func.__qualname__} is deprecated."
|
|
19
|
+
if new_function:
|
|
20
|
+
s += f" Use {new_function.__qualname__} instead."
|
|
21
|
+
warnings.warn(s, CCLDeprecationWarning)
|
|
22
|
+
return func(*args, **kwargs)
|
|
23
|
+
return wrapper
|
|
24
|
+
return decorator
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def deprecate_attr(getter=None, *, pairs=[]):
|
|
28
|
+
"""This decorator can be used to deprecate attributes,
|
|
29
|
+
warning users about it and pointing them to the new attribute.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
getter : slot wrapper ``__getattribute__``
|
|
34
|
+
This is the getter method to be decorated.
|
|
35
|
+
pairs : list of pairs
|
|
36
|
+
List of renaming pairs ``('old', 'new')``.
|
|
37
|
+
|
|
38
|
+
Example
|
|
39
|
+
-------
|
|
40
|
+
We have the legacy attribute ``old_name`` which we want to rename
|
|
41
|
+
to ``new_name``. To achieve this we decorate the ``__getattribute__``
|
|
42
|
+
method of the parent class in the main class body to retrieve the
|
|
43
|
+
``__getattr__`` method for the main class, like so:
|
|
44
|
+
|
|
45
|
+
>>> __getattr__ = deprecate_attr([('old_name', 'new_name')])(
|
|
46
|
+
super.__getattribute__)
|
|
47
|
+
|
|
48
|
+
Now, every time the attribute is called via its old name, the user will
|
|
49
|
+
be warned about the renaming, and the attribute value will be returned.
|
|
50
|
+
|
|
51
|
+
.. note:: Make sure that you bind ``__getattr__`` to the decorator,
|
|
52
|
+
rather than ``__getattribute__``, because ``__getattr__``
|
|
53
|
+
provides the fallback mechanism we want to use. Otherwise,
|
|
54
|
+
an infinite recursion will initiate.
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
if getter is None:
|
|
58
|
+
return functools.partial(deprecate_attr, pairs=pairs)
|
|
59
|
+
|
|
60
|
+
rename = dict(pairs)
|
|
61
|
+
|
|
62
|
+
@functools.wraps(getter)
|
|
63
|
+
def wrapper(cls, name):
|
|
64
|
+
if name in rename:
|
|
65
|
+
new_name = rename[name]
|
|
66
|
+
class_name = cls.__class__.__name__
|
|
67
|
+
warnings.warn(
|
|
68
|
+
f"Attribute {name} is deprecated in {class_name}. "
|
|
69
|
+
f"Pass the new name {new_name}.", CCLDeprecationWarning)
|
|
70
|
+
name = new_name
|
|
71
|
+
|
|
72
|
+
return cls.__getattribute__(name)
|
|
73
|
+
return wrapper
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
__all__ = ("CosmologyParams",)
|
|
2
|
+
|
|
3
|
+
from ... import lib
|
|
4
|
+
from . import CCLParameters
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CosmologyParams(CCLParameters, factory=lib.parameters):
|
|
8
|
+
"""Instances of this class hold cosmological parameters."""
|
|
9
|
+
|
|
10
|
+
def __getattribute__(self, key):
|
|
11
|
+
if key == "m_nu":
|
|
12
|
+
N_nu_mass = self._instance.N_nu_mass
|
|
13
|
+
nu_masses = lib.parameters_get_nu_masses(self._instance, N_nu_mass)
|
|
14
|
+
return nu_masses.tolist()
|
|
15
|
+
return super().__getattribute__(key)
|
|
16
|
+
|
|
17
|
+
def __setattr__(self, key, value):
|
|
18
|
+
if key == "m_nu":
|
|
19
|
+
self._instance.N_nu_mass = len(value)
|
|
20
|
+
return lib.parameters_m_nu_set_custom(self._instance, value)
|
|
21
|
+
super().__setattr__(key, value)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
__all__ = ("FFTLogParams",)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class FFTLogParams:
|
|
5
|
+
"""Objects of this class store the FFTLog accuracy parameters.
|
|
6
|
+
See documentation in :meth:`update_parameters` for a full
|
|
7
|
+
description of all allowed parameters.
|
|
8
|
+
"""
|
|
9
|
+
#: Anti-aliasing. Factor mulitplying the lower boundary.
|
|
10
|
+
padding_lo_fftlog = 0.1
|
|
11
|
+
#: Anti-aliasing. Factor mulitplying the upper boundary.
|
|
12
|
+
padding_hi_fftlog = 10.
|
|
13
|
+
|
|
14
|
+
#: Samples per decade for the Hankel transforms.
|
|
15
|
+
n_per_decade = 100
|
|
16
|
+
#: Extrapolation type (`linx_liny`, `linx_logy` etc.).
|
|
17
|
+
extrapol = "linx_liny"
|
|
18
|
+
|
|
19
|
+
#: Padding for intermediate transforms (lower bound).
|
|
20
|
+
padding_lo_extra = 0.1
|
|
21
|
+
#: Padding for intermediate transforms (upper bound).
|
|
22
|
+
padding_hi_extra = 10.
|
|
23
|
+
#: If True, high precision intermediate transforms.
|
|
24
|
+
large_padding_2D = False
|
|
25
|
+
|
|
26
|
+
#: Power law index used to prewhiten data before transform.
|
|
27
|
+
plaw_fourier = -1.5
|
|
28
|
+
#: Pre-whitening power law index for 2D and cumulative profiles.
|
|
29
|
+
plaw_projected = -1.0
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def params(self):
|
|
33
|
+
return ["padding_lo_fftlog", "padding_hi_fftlog", "n_per_decade",
|
|
34
|
+
"extrapol", "padding_lo_extra", "padding_hi_extra",
|
|
35
|
+
"large_padding_2D", "plaw_fourier", "plaw_projected"]
|
|
36
|
+
|
|
37
|
+
def to_dict(self):
|
|
38
|
+
""" Returns a dictionary containing this object's parameters.
|
|
39
|
+
"""
|
|
40
|
+
return {param: getattr(self, param) for param in self.params}
|
|
41
|
+
|
|
42
|
+
def __getitem__(self, name):
|
|
43
|
+
return getattr(self, name)
|
|
44
|
+
|
|
45
|
+
def __setattr__(self, name, value):
|
|
46
|
+
raise AttributeError("FFTLogParams can only be updated via "
|
|
47
|
+
"`updated_parameters`.")
|
|
48
|
+
|
|
49
|
+
def __repr__(self):
|
|
50
|
+
return repr(self.to_dict())
|
|
51
|
+
|
|
52
|
+
def __eq__(self, other):
|
|
53
|
+
if self is other:
|
|
54
|
+
True
|
|
55
|
+
if type(self) is not type(other):
|
|
56
|
+
return False
|
|
57
|
+
return self.to_dict() == other.to_dict()
|
|
58
|
+
|
|
59
|
+
def update_parameters(self, **kwargs):
|
|
60
|
+
"""Update the precision of FFTLog for the Hankel transforms.
|
|
61
|
+
|
|
62
|
+
Arguments
|
|
63
|
+
---------
|
|
64
|
+
padding_lo_fftlog: :obj:`float`
|
|
65
|
+
Factor by which the minimum scale is multiplied to avoid
|
|
66
|
+
aliasing. Default: 0.1.
|
|
67
|
+
padding_hi_fftlog: :obj:`float`
|
|
68
|
+
Factor by which the maximum scale is multiplied to avoid
|
|
69
|
+
aliasing. Default: 10.
|
|
70
|
+
n_per_decade : :obj:`float`
|
|
71
|
+
Samples per decade for the Hankel transforms. Default: 100.
|
|
72
|
+
extrapol : {'linx_liny', 'linx_logy'}
|
|
73
|
+
Extrapolation type when FFTLog has narrower output support.
|
|
74
|
+
Default ``'linx_liny'``.
|
|
75
|
+
padding_lo_extra: :obj:`float`
|
|
76
|
+
Additional minimum scale padding for double Hankel transforms,
|
|
77
|
+
used when computing 2D projected and cumulative profiles. In
|
|
78
|
+
these, the first transform goes from 3D real space to
|
|
79
|
+
Fourier, and the second transform goes from Fourier to 2D
|
|
80
|
+
real space.
|
|
81
|
+
Default: 0.1.
|
|
82
|
+
padding_hi_extra: :obj:`float`
|
|
83
|
+
As ``padding_lo_extra`` for the maximum scale.
|
|
84
|
+
Default: 10.
|
|
85
|
+
large_padding_2D : :obj:`bool`
|
|
86
|
+
Override ``padding_xx_extra`` in the intermediate transform,
|
|
87
|
+
and use ``padding_xx_fftlog``. The default is False.
|
|
88
|
+
plaw_fourier: :obj:`float`
|
|
89
|
+
FFTLog pre-whitens its arguments (makes them flatter) to avoid
|
|
90
|
+
aliasing. The ``plaw_fourier`` parameter describes the tilt of
|
|
91
|
+
the profile, :math:`P(r) \\propto r^{\\mathrm{tilt}}`, for
|
|
92
|
+
standard 3D transforms. Default: -1.5
|
|
93
|
+
plaw_fourier_projected: :obj:`float`
|
|
94
|
+
As ``plaw_fourier`` for 2D transforms (when computing 2D
|
|
95
|
+
projected or cumulative profiles. Default: -1.0.
|
|
96
|
+
"""
|
|
97
|
+
for name, value in kwargs.items():
|
|
98
|
+
if name not in self.params:
|
|
99
|
+
raise AttributeError(f"Parameter {name} does not exist.")
|
|
100
|
+
object.__setattr__(self, name, value)
|