sacc 1.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.
sacc/utils.py ADDED
@@ -0,0 +1,168 @@
1
+ import re
2
+
3
+ from astropy.table import Column
4
+ import numpy as np
5
+ import scipy.linalg
6
+
7
+ # These null values are used in place
8
+ # of missing values.
9
+ null_values = {
10
+ 'i': -1437530437530211245,
11
+ 'f': -1.4375304375e30,
12
+ 'U': '',
13
+ }
14
+
15
+
16
+ def hide_null_values(table):
17
+ """Replace None values in an astropy table
18
+ with a null value, and change the column type
19
+ to whatever suits the remaining data points
20
+
21
+ Parameters
22
+ ----------
23
+ table: astropy table
24
+ Table to modify in-place
25
+ """
26
+
27
+ for name, col in list(table.columns.items()):
28
+ if col.dtype.kind == 'O':
29
+ good_values = [x for x in col if x is not None]
30
+ good_kind = np.array(good_values).dtype.kind
31
+ null = null_values[good_kind]
32
+ good_col = np.array([null if x is None else x for x in col])
33
+ table[name] = Column(good_col)
34
+
35
+
36
+ def remove_dict_null_values(dictionary):
37
+ """Remove values in a dictionary that
38
+ correspond to the null values above.
39
+
40
+ Parameters
41
+ ----------
42
+ dictionary: dict
43
+ Dict (or subclass instance or other mapping) to modify in-place
44
+ """
45
+ # will figure out the list of keys to remove
46
+ deletes = []
47
+ for k, v in dictionary.items():
48
+ try:
49
+ dt = np.dtype(type(v)).kind
50
+ if v == null_values[dt]:
51
+ deletes.append(k)
52
+ except (TypeError, KeyError):
53
+ continue
54
+ for d in deletes:
55
+ del dictionary[d]
56
+
57
+
58
+ def unique_list(seq):
59
+ """
60
+ Find the unique elements in a list or other sequence
61
+ while maintaining the order. (i.e., remove any duplicated
62
+ elements but otherwise leave it the same)
63
+
64
+ Method from:
65
+ https://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-whilst-preserving-order
66
+
67
+ Parameters
68
+ ----------
69
+ seq: list or sequence
70
+ Any input object that can be iterated
71
+
72
+ Returns
73
+ -------
74
+ L: list
75
+ a new list of the unique objects
76
+ """
77
+ seen = set()
78
+ seen_add = seen.add
79
+ return [x for x in seq if not (x in seen or seen_add(x))]
80
+
81
+
82
+ class Namespace:
83
+ """
84
+ This helper class implements a very simple namespace object
85
+ designed to store strings with the same name as their contents
86
+ as a kind of simple string enum.
87
+
88
+ N = Namespace('a', 'b', 'c')
89
+
90
+ assert N.a=='a'
91
+
92
+ assert N['a']=='a'
93
+
94
+ assert N.index('b')==1
95
+ """
96
+ def __init__(self, *strings):
97
+ """
98
+ Create the object from a list of strings, which will become attributes
99
+ """
100
+ self._index = {}
101
+ n = 0
102
+ for s in strings:
103
+ self.__dict__[s] = s
104
+ self._index[s] = n
105
+ n += 1
106
+
107
+ def __contains__(self, s):
108
+ return hasattr(self, s)
109
+
110
+ def __getitem__(self, s):
111
+ return getattr(self, s)
112
+
113
+ def __str__(self):
114
+ return "\n".join(f"- {s}" for s in self._index)
115
+
116
+ def index(self, s):
117
+ return self._index[s]
118
+
119
+
120
+ def invert_spd_matrix(M, strict=True):
121
+ """
122
+ Invert a symmetric positive definite matrix.
123
+
124
+ SPD matrices (for example, covariance matrices) have only
125
+ positive eigenvalues.
126
+
127
+ Based on:
128
+ https://stackoverflow.com/questions/40703042/more-efficient-way-to-invert-a-matrix-knowing-it-is-symmetric-and-positive-semi
129
+
130
+ Parameters
131
+ ----------
132
+ M: 2d array
133
+ Matrix to invert
134
+
135
+ strict: bool, default=True
136
+ If True, require that the matrix is SPD.
137
+ If False, use a slower algorithm that will work on other matrices
138
+
139
+ Returns
140
+ -------
141
+ invM: 2d array
142
+ Inverse matrix
143
+
144
+ """
145
+ M = np.atleast_2d(M)
146
+
147
+ # In strict mode we use a method which will only work for SPD matrices,
148
+ # and raise an exception otherwise.
149
+ if strict:
150
+ L, _ = scipy.linalg.lapack.dpotrf(M, False, False)
151
+ invM, info = scipy.linalg.lapack.dpotri(L)
152
+ if info:
153
+ raise ValueError("Matrix is not symmetric-positive-definite")
154
+ else:
155
+ invM = np.triu(invM) + np.triu(invM, k=1).T
156
+ # Otherwise we use the generic (and also slower) method that will
157
+ # work if, due to numerical issues, the matrix is not quite SPD
158
+ else:
159
+ invM = np.linalg.inv(M)
160
+
161
+ return invM
162
+
163
+
164
+ def camel_case_split_and_lowercase(identifier):
165
+ matches = re.finditer('.+?(?:(?<=[a-z])(?=[A-Z])'
166
+ '|(?<=[A-Z])(?=[A-Z][a-z])|$)',
167
+ identifier)
168
+ return [m.group(0).lower() for m in matches]
sacc/windows.py ADDED
@@ -0,0 +1,334 @@
1
+ import numpy as np
2
+ from astropy.table import Table
3
+
4
+
5
+ class BaseWindow:
6
+ """Base class for window functions.
7
+
8
+ Window functions here are for 1D variables and describe
9
+ binnings from functions onto discrete values.
10
+
11
+ They are treated as a special kind of tag value in Sacc.
12
+
13
+ Subclasses describe common types of window function, including
14
+ a top hat between two values and a general tabulated
15
+ functional form.
16
+
17
+ This base class has class methods that can be used to turn
18
+ mixed lists of windows to/from astropy tables, for I/O.
19
+ """
20
+ _window_classes = {}
21
+
22
+ def __init_subclass__(cls, window_type):
23
+ # This gets called whenever a subclass is defined.
24
+ # The window_type argument is specified next to the
25
+ # base class in the subclass definition, e.g.
26
+ # window_typ='TopHat', as shown below
27
+ cls._window_classes[window_type] = cls
28
+ cls.window_type = window_type
29
+
30
+ @classmethod
31
+ def to_tables(cls, instance_list):
32
+ """Convert a list of BaseWindos to a list of tables.
33
+
34
+ This is called when saving data to file.
35
+
36
+ The input instances can be different subclasses, and no
37
+ ordering is maintained.
38
+
39
+ Parameters
40
+ ----------
41
+ instance_list: list
42
+ List of BaseWindow subclass instances
43
+
44
+ Returns
45
+ -------
46
+ table: list
47
+ List of astropy.table.Table instances
48
+ """
49
+ tables = []
50
+ for name, subcls in cls._window_classes.items():
51
+ # Pull out the relevant objects for this subclass.
52
+ # Note that we can't use isinstance here.
53
+ windows = [w for w in instance_list if type(w) == subcls]
54
+ if len(windows) > 0:
55
+ tables += subcls.to_tables(windows)
56
+ return tables
57
+
58
+ @classmethod
59
+ def from_tables(cls, table_list):
60
+ """Turn a list of astropy tables into window objects
61
+
62
+ This is called when loading data from file.
63
+
64
+ Parameters
65
+ ----------
66
+ instance_list: list
67
+ List of BaseWindow instances
68
+
69
+ Returns
70
+ -------
71
+ windows: dict
72
+ Dictionary of id -> Window instances
73
+ """
74
+ windows = {}
75
+ for table in table_list:
76
+ subclass_name = table.meta['SACCCLSS']
77
+ subclass = cls._window_classes[subclass_name]
78
+ # Different subclasses can handle this differently.
79
+ windows.update(subclass.from_table(table))
80
+ return windows
81
+
82
+
83
+ class TopHatWindow(BaseWindow, window_type='TopHat'):
84
+ """A window function that is constant between two values.
85
+
86
+ The top-hat is zero elsewhere.
87
+
88
+ In the case of discrete functions like ell window where it matters, these
89
+ window functions should follow the python convention and
90
+ the upper limit should be exclusive, so that you can use
91
+ range(win.min, win.max) to select the right ell values.
92
+
93
+ Parameters
94
+ ----------
95
+ min: int/float
96
+ The minimum value where the top-hat function equals 1
97
+
98
+ max: int/float
99
+ The maximum value where the top-hat function equals 1
100
+ """
101
+ def __init__(self, range_min, range_max):
102
+ """Create a top-hat window
103
+
104
+ Parameters
105
+ ----------
106
+ range_min: int/float
107
+ The minimum value where the top-hat function equals 1
108
+
109
+ range_max: int/float
110
+ The maximum value where the top-hat function equals 1
111
+
112
+ """
113
+ self.min = range_min
114
+ self.max = range_max
115
+
116
+ @classmethod
117
+ def to_tables(cls, window_list):
118
+ """Convert a list of Top-Hat windows to a list of astropy tables.
119
+
120
+ A single table is created for all the windows.
121
+
122
+ The tables contain an ID column which uniquely identifies the
123
+ window instance, but only whilst running a given python process -
124
+ it is not portable. It should not be used for anythng other than I/O.
125
+
126
+ Parameters
127
+ ----------
128
+ instance_list: list
129
+ List of TopHatWindow instances
130
+
131
+ Returns
132
+ -------
133
+ table: list
134
+ List of astropy.table.Table instances
135
+ """
136
+ mins = [w.min for w in window_list]
137
+ maxs = [w.max for w in window_list]
138
+ ids = [id(w) for w in window_list]
139
+ t = Table(data=[ids, mins, maxs], names=['id', 'min', 'max'])
140
+ t.meta['SACCTYPE'] = 'window'
141
+ t.meta['SACCCLSS'] = cls.window_type
142
+ t.meta['EXTNAME'] = 'window:' + cls.window_type
143
+ return [t]
144
+
145
+ @classmethod
146
+ def from_table(cls, table):
147
+ """Convert an astropy table to a dictionary of Top-Hat windows
148
+
149
+ Multiple windows are extracted from the single table.
150
+
151
+ Parameters
152
+ ----------
153
+ table: astropy.table.Table
154
+
155
+ Returns
156
+ -------
157
+ windows: dict
158
+ Dictionary of id -> TopHatWindow instances
159
+ """
160
+ return {row['id']: cls(row['min'], row['max']) for row in table}
161
+
162
+
163
+ class LogTopHatWindow(TopHatWindow, window_type='LogTopHat'):
164
+ """A window function that is log-constant between two values.
165
+
166
+ This object is the same as the TopHat form, except that in between
167
+ the min and max values it is assumed to be constant in the log of the
168
+ argument. The difference arises when this object is used elsewhere.
169
+ """
170
+ pass
171
+
172
+
173
+ class Window(BaseWindow, window_type='Standard'):
174
+ """The Window class defines a tabulated window function.
175
+
176
+ The class contains tabulated values of the abscissa (e.g. ell or theta) and
177
+ corresponding weights values for each one.
178
+
179
+ The function could be integrated or summed depending on the
180
+ context.
181
+
182
+ Parameters
183
+ ----------
184
+ values: array
185
+ The points at which the weights are defines
186
+ weight:
187
+ The weights corresponding to each value
188
+
189
+ """
190
+ def __init__(self, values, weight):
191
+ self.values = np.array(values)
192
+ self.weight = np.array(weight)
193
+
194
+ @classmethod
195
+ def to_tables(cls, window_list):
196
+ """Convert a list of windows to a list of astropy tables.
197
+
198
+ One table is created per window.
199
+
200
+ The tables contain an ID column which uniquely identifies the
201
+ window instance, but only whilst running a given python process -
202
+ it is not portable. It should not be used for anythng other than I/O.
203
+
204
+ Parameters
205
+ ----------
206
+ instance_list: list
207
+ List of Window instances
208
+
209
+ Returns
210
+ -------
211
+ table: list
212
+ List of astropy.table.Table instances
213
+ """
214
+ tables = []
215
+ for w in window_list:
216
+ cols = [w.values, w.weight]
217
+ names = ['values', 'weight']
218
+ t = Table(data=cols, names=names)
219
+ t.meta['SACCTYPE'] = 'window'
220
+ t.meta['SACCCLSS'] = cls.window_type
221
+ t.meta['SACCNAME'] = id(w)
222
+ t.meta['EXTNAME'] = 'window:' + cls.window_type
223
+ tables.append(t)
224
+ return tables
225
+
226
+ @classmethod
227
+ def from_table(cls, table):
228
+ """Convert an astropy table to a dictionary of Windows
229
+
230
+ One window is extracted from the table.
231
+
232
+ Parameters
233
+ ----------
234
+ table: astropy.table.Table
235
+
236
+ Returns
237
+ -------
238
+ windows: dict
239
+ Dictionary of id -> Window instances
240
+ """
241
+ return {table.meta['SACCNAME']: cls(table['values'], table['weight'])}
242
+
243
+
244
+ class BandpowerWindow(BaseWindow, window_type='Bandpower'):
245
+ """The BandpowerWindow class defines a tabulated for power
246
+ spectrum bandpowers.
247
+
248
+ The class contains tabulated values of ell and corresponding weights
249
+ values for each one. More than one set of weights can be used.
250
+
251
+ Parameters
252
+ ----------
253
+ values: array
254
+ An array of dimension (N_ell) containing the ell values at which the
255
+ weights are defined.
256
+ weight:
257
+ An array of dimensions (N_ell, N_weight) containing N_weight sets of
258
+ weights corresponding to each value.
259
+
260
+ """
261
+ def __init__(self, values, weight):
262
+ nl, nv = weight.shape
263
+ nell = len(values)
264
+ if nl != len(values):
265
+ raise ValueError(f"Wrong input shapes ${nl}!=${nell}")
266
+ self.nell = nell
267
+ self.nv = nv
268
+ self.values = np.array(values)
269
+ self.weight = np.array(weight)
270
+
271
+ @classmethod
272
+ def to_tables(cls, window_list):
273
+ """Convert a list of windows to a list of astropy tables.
274
+
275
+ One table is created per window.
276
+
277
+ The tables contain an ID column which uniquely identifies the
278
+ window instance, but only whilst running a given python process -
279
+ it is not portable. It should not be used for anythng other than I/O.
280
+
281
+ Parameters
282
+ ----------
283
+ instance_list: list
284
+ List of Window instances
285
+
286
+ Returns
287
+ -------
288
+ table: list
289
+ List of astropy.table.Table instances
290
+ """
291
+ tables = []
292
+ for w in window_list:
293
+ cols = [w.values, w.weight]
294
+ names = ['values', 'weight']
295
+ t = Table(data=cols, names=names)
296
+ t.meta['SACCTYPE'] = 'window'
297
+ t.meta['SACCCLSS'] = cls.window_type
298
+ t.meta['SACCNAME'] = id(w)
299
+ t.meta['EXTNAME'] = 'window:' + cls.window_type
300
+ tables.append(t)
301
+ return tables
302
+
303
+ @classmethod
304
+ def from_table(cls, table):
305
+ """Convert an astropy table to a dictionary of Windows
306
+
307
+ One window is extracted from the table.
308
+
309
+ Parameters
310
+ ----------
311
+ table: astropy.table.Table
312
+
313
+ Returns
314
+ -------
315
+ windows: dict
316
+ Dictionary of id -> Window instances
317
+ """
318
+ return {table.meta['SACCNAME']: cls(table['values'], table['weight'])}
319
+
320
+ def get_section(self, indices):
321
+ """Get part of this window function corresponding to the input
322
+ indices.
323
+
324
+ Parameters
325
+ ----------
326
+ indices: int or array_like
327
+ Indices to return.
328
+
329
+ Returns
330
+ -------
331
+ window: `Window`
332
+ A `Window object.
333
+ """
334
+ return self.__class__(self.values, self.weight[:, indices])
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: sacc
3
+ Version: 1.0
4
+ Summary: SACC - the LSST/DESC summary statistic data format library
5
+ Author-email: LSST DESC <joezuntz@googlemail.com>
6
+ License: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/LSSTDESC/sacc
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: scipy
13
+ Requires-Dist: numpy>=1.20
14
+ Requires-Dist: astropy
15
+ Provides-Extra: all
16
+ Requires-Dist: qp-prob[all]; extra == "all"
17
+ Requires-Dist: numpydoc; extra == "all"
18
+ Provides-Extra: doc
19
+ Requires-Dist: numpydoc; extra == "doc"
20
+ Provides-Extra: qp
21
+ Requires-Dist: qp-prob[all]; extra == "qp"
22
+ Dynamic: license-file
23
+
24
+ Sacc
25
+ ====
26
+
27
+ SACC (Save All Correlations and Covariances) is a format and reference library for general storage
28
+ of summary statistic measurements for the Dark Energy Science Collaboration (DESC) within the Large Synoptic
29
+ Survey Telescope (LSST) project.
30
+
31
+
32
+ Installation
33
+ ------------
34
+
35
+ You can install sacc with the command:
36
+
37
+ ``pip install sacc``
38
+
39
+ (For local installation you might need to add `--user`)
40
+
41
+ Or for development versions you can download the repository with git and install from there using ``python setup.py install``
42
+
43
+
44
+ Documentation & Examples
45
+ ------------------------
46
+
47
+ Documentation can be found [on ReadTheDocs](https://sacc.readthedocs.io/en/latest/).
48
+
49
+ The [examples directory](https://github.com/LSSTDESC/sacc/tree/master/examples) on github contains ipython notebooks showing various ways of constructing and using sacc data files.
50
+
51
+ If you have a problem you've not been able to debug, or a feature request/suggestion the you can [open an issue](https://github.com/LSSTDESC/sacc/issues) to discuss it.
52
+
53
+ Versions
54
+ --------
55
+
56
+ The current release is [version 0.12](https://github.com/LSSTDESC/sacc/releases/tag/0.12).
57
+
58
+ You can find a list of [previous releases here](https://github.com/LSSTDESC/sacc/releases). The releases above 0.2 are all backwards compatible; 0.1 is a previous version of the format.
59
+
60
+ The master branch includes more recent (non-released) development changes.
61
+
62
+
63
+ Citation
64
+ --------
65
+
66
+ Sacc has been submitted to the [Astrophysics Source Code Library](https://ascl.net/code/v/2277); follow the link that will appear there to NASA ADS to export a bibtex citation.
67
+
68
+ The core developers of Sacc are Joe Zuntz (maintainer), David Alonso, and Matt Becker.
@@ -0,0 +1,12 @@
1
+ sacc/__init__.py,sha256=gBQL_7lot-eVvroFsQAeM8_Gxaj5saR-hShiDLDwjV8,353
2
+ sacc/covariance.py,sha256=ZxeEI1zWNlMhh-ttUiX7r6j8qx5zKySw_zYRu6npq_o,16402
3
+ sacc/data_types.py,sha256=nsa6iM8ApRmMwb0GNQ-kO3LkgTMaJca-soC0G44TjAs,16285
4
+ sacc/sacc.py,sha256=cgc0p3wwTKF2WT089jDC9qh4TvOFks5MXR16kMKVHOY,51492
5
+ sacc/tracers.py,sha256=as4QLvStrposeneKLRPJxtCt-MOGFGvXOIm14yHVcFc,42893
6
+ sacc/utils.py,sha256=nmauWm_bXNFMWxGomM6GlgLM2bPxG_awYvcE67XF07s,4440
7
+ sacc/windows.py,sha256=Ww6z23ys17pv_QbDHGwHEqQWauD1jk6aWOiQ4Riis2U,10137
8
+ sacc-1.0.dist-info/licenses/LICENSE,sha256=WMLhPVmrUk6KoMHcLwY1ynIJcA7id_bfU-QSSiCAxtI,1469
9
+ sacc-1.0.dist-info/METADATA,sha256=Vo12b76DVXcvMBQdWYK38nOCEKRPikSb-0OMv1RDa78,2396
10
+ sacc-1.0.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
11
+ sacc-1.0.dist-info/top_level.txt,sha256=nyd_Bzl4Ly4EGXdgYFa0MHs8CYGAOIGPG1PhQTZsSdM,5
12
+ sacc-1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (79.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,11 @@
1
+ Copyright 2019-2023 The SACC Developers
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ sacc