sacc 1.0.2__py3-none-any.whl → 2.0.1__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/__init__.py +4 -1
- sacc/covariance.py +202 -96
- sacc/data_types.py +64 -9
- sacc/io.py +414 -0
- sacc/sacc.py +372 -164
- sacc/tracer_uncertainty/__init__.py +1 -0
- sacc/tracer_uncertainty/base.py +34 -0
- sacc/tracer_uncertainty/nz.py +287 -0
- sacc/tracers/__init__.py +6 -0
- sacc/tracers/base.py +127 -0
- sacc/tracers/clusters.py +332 -0
- sacc/tracers/maps.py +206 -0
- sacc/tracers/misc.py +87 -0
- sacc/tracers/nz.py +285 -0
- sacc/tracers/survey.py +75 -0
- sacc/utils.py +46 -2
- sacc/windows.py +116 -102
- {sacc-1.0.2.dist-info → sacc-2.0.1.dist-info}/METADATA +6 -4
- sacc-2.0.1.dist-info/RECORD +22 -0
- {sacc-1.0.2.dist-info → sacc-2.0.1.dist-info}/WHEEL +1 -1
- sacc/tracers.py +0 -1217
- sacc-1.0.2.dist-info/RECORD +0 -12
- {sacc-1.0.2.dist-info → sacc-2.0.1.dist-info}/licenses/LICENSE +0 -0
- {sacc-1.0.2.dist-info → sacc-2.0.1.dist-info}/top_level.txt +0 -0
sacc/tracers/nz.py
ADDED
@@ -0,0 +1,285 @@
|
|
1
|
+
from .base import BaseTracer, ONE_OBJECT_PER_TABLE, ONE_OBJECT_MULTIPLE_TABLES
|
2
|
+
from astropy.table import Table
|
3
|
+
import numpy as np
|
4
|
+
from ..utils import remove_dict_null_values
|
5
|
+
|
6
|
+
class NZTracer(BaseTracer, type_name='NZ'):
|
7
|
+
"""
|
8
|
+
A Tracer type for tomographic n(z) data.
|
9
|
+
|
10
|
+
Takes two arguments arrays of z and n(z)
|
11
|
+
|
12
|
+
Parameters
|
13
|
+
----------
|
14
|
+
name: str
|
15
|
+
The name for this specific tracer, e.g. a
|
16
|
+
tomographic bin identifier.
|
17
|
+
|
18
|
+
z: array
|
19
|
+
Redshift sample values
|
20
|
+
|
21
|
+
nz: array
|
22
|
+
Number density n(z) at redshift sample points.
|
23
|
+
|
24
|
+
extra_columns: dict[str: array] or dict[int: array]
|
25
|
+
Additional estimates of the same n(z), by name
|
26
|
+
"""
|
27
|
+
|
28
|
+
storage_type = ONE_OBJECT_PER_TABLE
|
29
|
+
|
30
|
+
def __init__(self, name, z, nz,
|
31
|
+
extra_columns=None, **kwargs):
|
32
|
+
"""
|
33
|
+
Create a tracer corresponding to a distribution in redshift n(z),
|
34
|
+
for example of galaxies.
|
35
|
+
|
36
|
+
Parameters
|
37
|
+
----------
|
38
|
+
name: str
|
39
|
+
The name for this specific tracer, e.g. a
|
40
|
+
tomographic bin identifier.
|
41
|
+
|
42
|
+
z: array
|
43
|
+
Redshift sample values
|
44
|
+
|
45
|
+
nz: array
|
46
|
+
Number density n(z) at redshift sample points.
|
47
|
+
|
48
|
+
extra_columns: dict[str:array]
|
49
|
+
Optional, default=None. Additional realizations or
|
50
|
+
estimates of the same n(z), by name.
|
51
|
+
|
52
|
+
Returns
|
53
|
+
-------
|
54
|
+
instance: NZTracer object
|
55
|
+
An instance of this class
|
56
|
+
"""
|
57
|
+
super().__init__(name, **kwargs)
|
58
|
+
self.z = np.array(z)
|
59
|
+
self.nz = np.array(nz)
|
60
|
+
self.extra_columns = {} if extra_columns is None else extra_columns
|
61
|
+
|
62
|
+
def to_table(self):
|
63
|
+
"""Convert a list of NZTracers to a list of astropy tables
|
64
|
+
|
65
|
+
This is used when saving data to a file.
|
66
|
+
One table is generated per tracer.
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
instance_list: list
|
71
|
+
List of tracer instances
|
72
|
+
|
73
|
+
Returns
|
74
|
+
-------
|
75
|
+
tables: list
|
76
|
+
List of astropy tables
|
77
|
+
"""
|
78
|
+
names = ['z', 'nz']
|
79
|
+
cols = [self.z, self.nz]
|
80
|
+
for nz_id, col in self.extra_columns.items():
|
81
|
+
names.append(str(nz_id))
|
82
|
+
cols.append(col)
|
83
|
+
table = Table(data=cols, names=names)
|
84
|
+
table.meta['SACCQTTY'] = self.quantity
|
85
|
+
# This will also get set at the higher level
|
86
|
+
# if the tracer is save to a file, but for
|
87
|
+
# testing it's useful to have it here too.
|
88
|
+
table.meta['SACCNAME'] = self.name
|
89
|
+
for key, value in self.metadata.items():
|
90
|
+
table.meta['META_'+key] = value
|
91
|
+
remove_dict_null_values(table.meta)
|
92
|
+
return table
|
93
|
+
|
94
|
+
@classmethod
|
95
|
+
def from_table(cls, table):
|
96
|
+
"""Convert an astropy table into a an n(z) tracer
|
97
|
+
|
98
|
+
This is used when loading data from a file.
|
99
|
+
|
100
|
+
Parameters
|
101
|
+
----------
|
102
|
+
table: astropy.table.Table
|
103
|
+
Must contain the appropriate data, for example as saved
|
104
|
+
by to_table.
|
105
|
+
|
106
|
+
Returns
|
107
|
+
-------
|
108
|
+
tracers: dict
|
109
|
+
Dict mapping string names to tracer objects.
|
110
|
+
Only contains one key/value pair for the one tracer.
|
111
|
+
"""
|
112
|
+
name = table.meta['SACCNAME']
|
113
|
+
quantity = table.meta.get('SACCQTTY', 'generic')
|
114
|
+
z = table['z']
|
115
|
+
nz = table['nz']
|
116
|
+
extra_columns = {}
|
117
|
+
for col in table.columns.values():
|
118
|
+
if col.name not in ['z', 'nz']:
|
119
|
+
extra_columns[col.name] = col.data
|
120
|
+
|
121
|
+
metadata = {}
|
122
|
+
for key, value in table.meta.items():
|
123
|
+
if key.startswith("META_"):
|
124
|
+
metadata[key[5:]] = value
|
125
|
+
return cls(name, z, nz,
|
126
|
+
quantity=quantity,
|
127
|
+
extra_columns=extra_columns,
|
128
|
+
metadata=metadata)
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
class QPNZTracer(BaseTracer, type_name='QPNZ'):
|
133
|
+
"""
|
134
|
+
A Tracer type for tomographic n(z) data represented as a `qp.Ensemble`
|
135
|
+
|
136
|
+
Takes a `qp.Ensemble` and optionally a redshift array.
|
137
|
+
|
138
|
+
Requires the `qp` and `tables_io` packages to be installed.
|
139
|
+
|
140
|
+
Parameters
|
141
|
+
----------
|
142
|
+
name: str
|
143
|
+
The name for this specific tracer, e.g. a
|
144
|
+
tomographic bin identifier.
|
145
|
+
|
146
|
+
ensemble: qp.Ensemble
|
147
|
+
The qp.ensemble in questions
|
148
|
+
"""
|
149
|
+
|
150
|
+
storage_type = ONE_OBJECT_MULTIPLE_TABLES
|
151
|
+
|
152
|
+
def __init__(self, name, ens, z=None, nz=None, **kwargs):
|
153
|
+
"""
|
154
|
+
Create a tracer corresponding to a distribution in redshift n(z),
|
155
|
+
for example of galaxies.
|
156
|
+
|
157
|
+
Parameters
|
158
|
+
----------
|
159
|
+
name: str
|
160
|
+
The name for this specific tracer, e.g. a
|
161
|
+
tomographic bin identifier.
|
162
|
+
|
163
|
+
ensemble: qp.Ensemble
|
164
|
+
The qp.ensemble in questions
|
165
|
+
|
166
|
+
z: array
|
167
|
+
Optional grid of redshift values at which to evaluate the ensemble.
|
168
|
+
If left as None then the ensemble metadata is checked for a grid.
|
169
|
+
If that is not present then no redshift grid is saved.
|
170
|
+
nz: array
|
171
|
+
Optional, default=None. establishes a fiducial n(z) for the ensemble.
|
172
|
+
This can later be used to compute systematic biases in the ensemble.
|
173
|
+
|
174
|
+
Returns
|
175
|
+
-------
|
176
|
+
instance: NZTracer object
|
177
|
+
An instance of this class
|
178
|
+
"""
|
179
|
+
super().__init__(name, **kwargs)
|
180
|
+
self.ensemble = ens
|
181
|
+
if z is None:
|
182
|
+
ens_meta = ens.metadata
|
183
|
+
if 'bins' in list(ens_meta.keys()):
|
184
|
+
z = ens_meta['bins'][0]
|
185
|
+
self.z = z
|
186
|
+
if z is None:
|
187
|
+
self.nz = None
|
188
|
+
else:
|
189
|
+
if nz is not None:
|
190
|
+
if len(nz) != len(z):
|
191
|
+
raise ValueError("nz must have the same length as z")
|
192
|
+
self.nz = nz
|
193
|
+
else:
|
194
|
+
nz = np.atleast_2d(ens.pdf(z))
|
195
|
+
self.nz = np.mean(nz, axis=0)
|
196
|
+
|
197
|
+
def to_tables(self):
|
198
|
+
"""Convert a list of NZTracers to a list of astropy tables
|
199
|
+
|
200
|
+
This is used when saving data to a file.
|
201
|
+
Two or three tables are generated per tracer.
|
202
|
+
|
203
|
+
Parameters
|
204
|
+
----------
|
205
|
+
instance_list: list
|
206
|
+
List of tracer instances
|
207
|
+
|
208
|
+
Returns
|
209
|
+
-------
|
210
|
+
tables: list
|
211
|
+
List of astropy tables
|
212
|
+
"""
|
213
|
+
from ..utils import convert_to_astropy_table
|
214
|
+
tables = {}
|
215
|
+
|
216
|
+
table_dict = self.ensemble.build_tables()
|
217
|
+
|
218
|
+
data_table = convert_to_astropy_table(table_dict['data'])
|
219
|
+
data_table.meta['SACCQTTY'] = self.quantity
|
220
|
+
data_table.meta['SACCNAME'] = self.name
|
221
|
+
tables["data"] = data_table
|
222
|
+
|
223
|
+
meta_table = convert_to_astropy_table(table_dict['meta'])
|
224
|
+
meta_table.meta['SACCQTTY'] = self.quantity
|
225
|
+
meta_table.meta['SACCNAME'] = self.name
|
226
|
+
|
227
|
+
for kk, vv in self.metadata.items():
|
228
|
+
meta_table.meta['META_'+kk] = vv
|
229
|
+
|
230
|
+
tables["meta"] = meta_table
|
231
|
+
|
232
|
+
if 'ancil' in table_dict:
|
233
|
+
ancil_table = convert_to_astropy_table(table_dict['ancil'])
|
234
|
+
ancil_table.meta['SACCQTTY'] = self.quantity
|
235
|
+
ancil_table.meta['SACCNAME'] = self.name
|
236
|
+
tables["ancil"] = ancil_table
|
237
|
+
|
238
|
+
if self.z is not None:
|
239
|
+
names = ['z', 'nz']
|
240
|
+
cols = [self.z, self.nz]
|
241
|
+
fid_table = Table(data=cols, names=names)
|
242
|
+
fid_table.meta['SACCQTTY'] = self.quantity
|
243
|
+
fid_table.meta['SACCNAME'] = self.name
|
244
|
+
tables["fid"] = fid_table
|
245
|
+
|
246
|
+
|
247
|
+
return tables
|
248
|
+
|
249
|
+
@classmethod
|
250
|
+
def from_tables(cls, tables):
|
251
|
+
"""Convert a dict of astropy tables into a tracer
|
252
|
+
|
253
|
+
This is used when loading data from a file.
|
254
|
+
A single tracer object is read from the table.
|
255
|
+
|
256
|
+
Parameters
|
257
|
+
----------
|
258
|
+
tables: dict[str,astropy.table.Table]
|
259
|
+
Must contain the appropriate data, for example as saved
|
260
|
+
by to_tables.
|
261
|
+
|
262
|
+
Returns
|
263
|
+
-------
|
264
|
+
tracer: QPNZTracer
|
265
|
+
"""
|
266
|
+
import qp
|
267
|
+
|
268
|
+
|
269
|
+
meta_table = tables['meta']
|
270
|
+
if 'fid' in tables:
|
271
|
+
z = tables['fid']['z']
|
272
|
+
nz = tables['fid']['nz']
|
273
|
+
else:
|
274
|
+
z = None
|
275
|
+
nz = None
|
276
|
+
ensemble = qp.from_tables(tables)
|
277
|
+
name = meta_table.meta['SACCNAME']
|
278
|
+
quantity = meta_table.meta.get('SACCQTTY', 'generic')
|
279
|
+
metadata = {}
|
280
|
+
for key, value in meta_table.meta.items():
|
281
|
+
if key.startswith("META_"):
|
282
|
+
metadata[key[5:]] = value
|
283
|
+
return cls(name, ensemble, z=z, nz=nz,
|
284
|
+
quantity=quantity,
|
285
|
+
metadata=metadata)
|
sacc/tracers/survey.py
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
from .base import BaseTracer, MULTIPLE_OBJECTS_PER_TABLE
|
2
|
+
from astropy.table import Table
|
3
|
+
|
4
|
+
|
5
|
+
class SurveyTracer(BaseTracer, type_name="survey"): # type: ignore
|
6
|
+
"""A tracer for the survey definition. It shall
|
7
|
+
be used to filter data related to a given survey
|
8
|
+
and to provide the survey sky-area of analysis."""
|
9
|
+
|
10
|
+
storage_type = MULTIPLE_OBJECTS_PER_TABLE
|
11
|
+
|
12
|
+
def __eq__(self, other) -> bool:
|
13
|
+
"""Test for equality. If :python:`other` is not a
|
14
|
+
:python:`SurveyTracer`, then it is not equal to :python:`self`.
|
15
|
+
Otherwise, they are equal if names and the sky-areas are equal."""
|
16
|
+
if not isinstance(other, SurveyTracer):
|
17
|
+
return False
|
18
|
+
return self.name == other.name and self.sky_area == other.sky_area
|
19
|
+
|
20
|
+
def __init__(self, name: str, sky_area: float, **kwargs):
|
21
|
+
"""
|
22
|
+
Create a tracer corresponding to the survey definition.
|
23
|
+
|
24
|
+
:param name: The name of the tracer
|
25
|
+
:param sky_area: The survey's sky area in square degrees
|
26
|
+
"""
|
27
|
+
super().__init__(name, **kwargs)
|
28
|
+
self.sky_area = sky_area
|
29
|
+
|
30
|
+
@classmethod
|
31
|
+
def to_table(cls, instance_list):
|
32
|
+
"""Convert a list of SurveyTracer to a list of astropy tables
|
33
|
+
|
34
|
+
This is used when saving data to a file.
|
35
|
+
One table is generated with the information for all the tracers.
|
36
|
+
|
37
|
+
:param instance_list: List of tracer instances
|
38
|
+
:return: List of astropy tables with one table
|
39
|
+
"""
|
40
|
+
names = ["name", "quantity", "sky_area"]
|
41
|
+
|
42
|
+
cols = [
|
43
|
+
[obj.name for obj in instance_list],
|
44
|
+
[obj.quantity for obj in instance_list],
|
45
|
+
[obj.sky_area for obj in instance_list],
|
46
|
+
]
|
47
|
+
|
48
|
+
table = Table(data=cols, names=names)
|
49
|
+
table.meta["SACCTYPE"] = "tracer"
|
50
|
+
table.meta["SACCCLSS"] = cls.type_name
|
51
|
+
table.meta["EXTNAME"] = f"tracer:{cls.type_name}"
|
52
|
+
return table
|
53
|
+
|
54
|
+
@classmethod
|
55
|
+
def from_table(cls, table):
|
56
|
+
"""Convert an astropy table into a dictionary of tracers
|
57
|
+
|
58
|
+
This is used when loading data from a file.
|
59
|
+
One tracer object is created for each "row" in each table.
|
60
|
+
|
61
|
+
:param table_list: List of astropy tables
|
62
|
+
:return: Dictionary of tracers
|
63
|
+
"""
|
64
|
+
tracers = {}
|
65
|
+
|
66
|
+
for row in table:
|
67
|
+
name = row["name"]
|
68
|
+
quantity = row["quantity"]
|
69
|
+
sky_area = row["sky_area"]
|
70
|
+
tracers[name] = cls(
|
71
|
+
name,
|
72
|
+
quantity=quantity,
|
73
|
+
sky_area=sky_area,
|
74
|
+
)
|
75
|
+
return tracers
|
sacc/utils.py
CHANGED
@@ -151,8 +151,7 @@ def invert_spd_matrix(M, strict=True):
|
|
151
151
|
invM, info = scipy.linalg.lapack.dpotri(L)
|
152
152
|
if info:
|
153
153
|
raise ValueError("Matrix is not symmetric-positive-definite")
|
154
|
-
|
155
|
-
invM = np.triu(invM) + np.triu(invM, k=1).T
|
154
|
+
invM = np.triu(invM) + np.triu(invM, k=1).T
|
156
155
|
# Otherwise we use the generic (and also slower) method that will
|
157
156
|
# work if, due to numerical issues, the matrix is not quite SPD
|
158
157
|
else:
|
@@ -166,3 +165,48 @@ def camel_case_split_and_lowercase(identifier):
|
|
166
165
|
'|(?<=[A-Z])(?=[A-Z][a-z])|$)',
|
167
166
|
identifier)
|
168
167
|
return [m.group(0).lower() for m in matches]
|
168
|
+
|
169
|
+
|
170
|
+
def convert_to_astropy_table(obj):
|
171
|
+
try:
|
172
|
+
from tables_io.convUtils import convertToApTables
|
173
|
+
version = 1
|
174
|
+
except ImportError:
|
175
|
+
try:
|
176
|
+
from tables_io import convert_table
|
177
|
+
version = 2
|
178
|
+
except ImportError:
|
179
|
+
raise ImportError("Error importing table conversion tool from tables_io. "
|
180
|
+
"Maybe they changed its name again. Please open an issue, "
|
181
|
+
"assuming you have tables_io installed.")
|
182
|
+
|
183
|
+
if version == 1:
|
184
|
+
return convertToApTables(obj)
|
185
|
+
if version == 2:
|
186
|
+
return convert_table(obj, "astropyTable")
|
187
|
+
raise ValueError("Unknown version of tables_io conversion tool.")
|
188
|
+
|
189
|
+
|
190
|
+
def numpy_to_vanilla(x):
|
191
|
+
"""
|
192
|
+
Convert a NumPy scalar type to its corresponding Python built-in type.
|
193
|
+
|
194
|
+
Parameters
|
195
|
+
----------
|
196
|
+
x : numpy scalar
|
197
|
+
A NumPy scalar value (e.g., np.str_, np.int64, np.float64, np.bool).
|
198
|
+
|
199
|
+
Returns
|
200
|
+
-------
|
201
|
+
object
|
202
|
+
The equivalent Python built-in type (e.g., str, int, float, bool).
|
203
|
+
"""
|
204
|
+
if type(x) == np.str_:
|
205
|
+
x = str(x)
|
206
|
+
elif type(x) == np.int64:
|
207
|
+
x = int(x)
|
208
|
+
elif type(x) == np.float64:
|
209
|
+
x = float(x)
|
210
|
+
elif type(x) == np.bool:
|
211
|
+
x = bool(x)
|
212
|
+
return x
|