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.
Files changed (171) hide show
  1. pyccl/.gitignore +1 -0
  2. pyccl/CMakeLists.txt +42 -0
  3. pyccl/__init__.py +47 -0
  4. pyccl/_ccllib.so +0 -0
  5. pyccl/_core/__init__.py +4 -0
  6. pyccl/_core/caching.py +303 -0
  7. pyccl/_core/deprecations.py +73 -0
  8. pyccl/_core/parameters/__init__.py +3 -0
  9. pyccl/_core/parameters/cosmology_params.py +21 -0
  10. pyccl/_core/parameters/fftlog_params.py +100 -0
  11. pyccl/_core/parameters/parameters_base.py +141 -0
  12. pyccl/_core/repr_.py +385 -0
  13. pyccl/_core/schema.py +376 -0
  14. pyccl/background.py +516 -0
  15. pyccl/baryons/__init__.py +4 -0
  16. pyccl/baryons/baccoemu_baryons.py +223 -0
  17. pyccl/baryons/baryons_base.py +41 -0
  18. pyccl/baryons/schneider15.py +96 -0
  19. pyccl/baryons/vandaalen19.py +111 -0
  20. pyccl/boltzmann.py +499 -0
  21. pyccl/ccl.i +61 -0
  22. pyccl/ccl_background.i +131 -0
  23. pyccl/ccl_cls.i +114 -0
  24. pyccl/ccl_core.i +48 -0
  25. pyccl/ccl_correlation.i +100 -0
  26. pyccl/ccl_covs.i +96 -0
  27. pyccl/ccl_f1d.i +54 -0
  28. pyccl/ccl_fftlog.i +109 -0
  29. pyccl/ccl_mass_conversion.i +32 -0
  30. pyccl/ccl_musigma.i +55 -0
  31. pyccl/ccl_neutrinos.i +30 -0
  32. pyccl/ccl_pk2d.i +65 -0
  33. pyccl/ccl_power.i +64 -0
  34. pyccl/ccl_sigM.i +41 -0
  35. pyccl/ccl_tk3d.i +58 -0
  36. pyccl/ccl_tracers.i +244 -0
  37. pyccl/ccl_utils.i +183 -0
  38. pyccl/ccllib.py +1788 -0
  39. pyccl/cells.py +175 -0
  40. pyccl/correlations.py +363 -0
  41. pyccl/cosmology.py +1001 -0
  42. pyccl/covariances.py +378 -0
  43. pyccl/emulators/__init__.py +4 -0
  44. pyccl/emulators/baccoemu_linear_pk.py +119 -0
  45. pyccl/emulators/baccoemu_nonlinear_pk.py +121 -0
  46. pyccl/emulators/cosmicemu_pk.py +245 -0
  47. pyccl/emulators/data/CosmicEmu_MTII_2017_Pcb.npz +0 -0
  48. pyccl/emulators/data/CosmicEmu_MTII_2017_Ptot.npz +0 -0
  49. pyccl/emulators/data/CosmicEmu_MTIV_2022_Pcb.npz +0 -0
  50. pyccl/emulators/data/CosmicEmu_MTIV_2022_Ptot.npz +0 -0
  51. pyccl/emulators/emu_base.py +58 -0
  52. pyccl/errors.py +91 -0
  53. pyccl/halos/__init__.py +11 -0
  54. pyccl/halos/concentration/__init__.py +8 -0
  55. pyccl/halos/concentration/bhattacharya13.py +37 -0
  56. pyccl/halos/concentration/constant.py +27 -0
  57. pyccl/halos/concentration/diemer15.py +52 -0
  58. pyccl/halos/concentration/duffy08.py +39 -0
  59. pyccl/halos/concentration/ishiyama21.py +97 -0
  60. pyccl/halos/concentration/klypin11.py +25 -0
  61. pyccl/halos/concentration/prada12.py +54 -0
  62. pyccl/halos/halo_model.py +444 -0
  63. pyccl/halos/halo_model_base.py +291 -0
  64. pyccl/halos/hbias/__init__.py +5 -0
  65. pyccl/halos/hbias/bhattacharya11.py +38 -0
  66. pyccl/halos/hbias/sheth01.py +40 -0
  67. pyccl/halos/hbias/sheth99.py +48 -0
  68. pyccl/halos/hbias/tinker10.py +47 -0
  69. pyccl/halos/hmfunc/__init__.py +12 -0
  70. pyccl/halos/hmfunc/angulo12.py +37 -0
  71. pyccl/halos/hmfunc/bocquet16.py +100 -0
  72. pyccl/halos/hmfunc/bocquet20.py +79 -0
  73. pyccl/halos/hmfunc/despali16.py +57 -0
  74. pyccl/halos/hmfunc/jenkins01.py +35 -0
  75. pyccl/halos/hmfunc/nishimichi19.py +96 -0
  76. pyccl/halos/hmfunc/press74.py +33 -0
  77. pyccl/halos/hmfunc/sheth99.py +51 -0
  78. pyccl/halos/hmfunc/tinker08.py +55 -0
  79. pyccl/halos/hmfunc/tinker10.py +86 -0
  80. pyccl/halos/hmfunc/watson13.py +66 -0
  81. pyccl/halos/massdef.py +368 -0
  82. pyccl/halos/pk_1pt.py +75 -0
  83. pyccl/halos/pk_2pt.py +232 -0
  84. pyccl/halos/pk_4pt.py +1660 -0
  85. pyccl/halos/profiles/__init__.py +8 -0
  86. pyccl/halos/profiles/cib_shang12.py +276 -0
  87. pyccl/halos/profiles/einasto.py +153 -0
  88. pyccl/halos/profiles/hernquist.py +215 -0
  89. pyccl/halos/profiles/hod.py +403 -0
  90. pyccl/halos/profiles/ia.py +439 -0
  91. pyccl/halos/profiles/nfw.py +206 -0
  92. pyccl/halos/profiles/pressure_gnfw.py +245 -0
  93. pyccl/halos/profiles/profile_base.py +521 -0
  94. pyccl/halos/profiles_2pt.py +239 -0
  95. pyccl/modified_gravity/__init__.py +2 -0
  96. pyccl/modified_gravity/modified_gravity_base.py +8 -0
  97. pyccl/modified_gravity/mu_Sigma.py +47 -0
  98. pyccl/neutrinos.py +91 -0
  99. pyccl/nl_pt/__init__.py +4 -0
  100. pyccl/nl_pt/bacco_lbias.py +491 -0
  101. pyccl/nl_pt/ept.py +696 -0
  102. pyccl/nl_pt/lpt.py +485 -0
  103. pyccl/nl_pt/tracers.py +242 -0
  104. pyccl/nonlimber/__init__.py +1 -0
  105. pyccl/nonlimber/_nonlimber_FKEM.py +472 -0
  106. pyccl/numpy.i +2970 -0
  107. pyccl/pk2d.py +568 -0
  108. pyccl/power.py +208 -0
  109. pyccl/pyutils.py +760 -0
  110. pyccl/tests/__init__.py +0 -0
  111. pyccl/tests/conftest.py +23 -0
  112. pyccl/tests/test__caching.py +168 -0
  113. pyccl/tests/test_bacco_lbias_power.py +298 -0
  114. pyccl/tests/test_baccoemu.py +162 -0
  115. pyccl/tests/test_background.py +255 -0
  116. pyccl/tests/test_baryons.py +67 -0
  117. pyccl/tests/test_baryons_vd19.py +66 -0
  118. pyccl/tests/test_cclerror.py +104 -0
  119. pyccl/tests/test_cclobject.py +168 -0
  120. pyccl/tests/test_cells.py +274 -0
  121. pyccl/tests/test_concentration.py +95 -0
  122. pyccl/tests/test_correlations.py +136 -0
  123. pyccl/tests/test_cosmicemu.py +36 -0
  124. pyccl/tests/test_cosmology.py +313 -0
  125. pyccl/tests/test_cosmology_parameters.py +343 -0
  126. pyccl/tests/test_covariances.py +173 -0
  127. pyccl/tests/test_ept_power.py +289 -0
  128. pyccl/tests/test_fftlog.py +96 -0
  129. pyccl/tests/test_gsl_splines.py +34 -0
  130. pyccl/tests/test_halofit_highz.py +54 -0
  131. pyccl/tests/test_halomodel.py +52 -0
  132. pyccl/tests/test_hashing.py +34 -0
  133. pyccl/tests/test_hbias.py +55 -0
  134. pyccl/tests/test_hmcalculator_integrals.py +99 -0
  135. pyccl/tests/test_hmcalculator_number_counts.py +165 -0
  136. pyccl/tests/test_hmfunc.py +244 -0
  137. pyccl/tests/test_lpt_power.py +171 -0
  138. pyccl/tests/test_m2r_sM.py +31 -0
  139. pyccl/tests/test_massdef.py +122 -0
  140. pyccl/tests/test_massfunction.py +47 -0
  141. pyccl/tests/test_mg.py +128 -0
  142. pyccl/tests/test_neutrinos.py +20 -0
  143. pyccl/tests/test_nonlin_camb_power.py +60 -0
  144. pyccl/tests/test_pk2d.py +481 -0
  145. pyccl/tests/test_pkhm.py +298 -0
  146. pyccl/tests/test_power.py +512 -0
  147. pyccl/tests/test_power_mu_sigma_sigma8norm.py +96 -0
  148. pyccl/tests/test_profiles.py +741 -0
  149. pyccl/tests/test_pt_tracers.py +58 -0
  150. pyccl/tests/test_pyutils.py +11 -0
  151. pyccl/tests/test_resampling.py +65 -0
  152. pyccl/tests/test_spline_integ.py +67 -0
  153. pyccl/tests/test_swig_interface.py +138 -0
  154. pyccl/tests/test_tk3d.py +233 -0
  155. pyccl/tests/test_tkk1h.py +114 -0
  156. pyccl/tests/test_tkk2h.py +326 -0
  157. pyccl/tests/test_tkk3h.py +211 -0
  158. pyccl/tests/test_tkk4h.py +155 -0
  159. pyccl/tests/test_tkk_separable_growth.py +207 -0
  160. pyccl/tests/test_tkkcNG.py +108 -0
  161. pyccl/tests/test_tkkssc.py +236 -0
  162. pyccl/tests/test_tracers.py +502 -0
  163. pyccl/tests/test_yaml.py +79 -0
  164. pyccl/tk3d.py +257 -0
  165. pyccl/tracers.py +1120 -0
  166. pyccl-3.3.0.dist-info/METADATA +160 -0
  167. pyccl-3.3.0.dist-info/RECORD +171 -0
  168. pyccl-3.3.0.dist-info/WHEEL +5 -0
  169. pyccl-3.3.0.dist-info/licenses/LICENSE +27 -0
  170. pyccl-3.3.0.dist-info/licenses/LICENSE_COSMICEMU +10 -0
  171. 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
@@ -0,0 +1,4 @@
1
+ from .parameters import *
2
+ from .caching import *
3
+ from .schema import *
4
+ from .deprecations import *
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,3 @@
1
+ from .parameters_base import *
2
+ from .cosmology_params import *
3
+ from .fftlog_params import *
@@ -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)