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/clusters.py
ADDED
@@ -0,0 +1,332 @@
|
|
1
|
+
from .base import BaseTracer, MULTIPLE_OBJECTS_PER_TABLE
|
2
|
+
from astropy.table import Table
|
3
|
+
|
4
|
+
class BinZTracer(BaseTracer, type_name="bin_z"): # type: ignore
|
5
|
+
"""A tracer for a single redshift bin. The tracer shall
|
6
|
+
be used for binned data where we want a desired quantity
|
7
|
+
per interval of redshift, such that we only need the data
|
8
|
+
for a given interval instead of at individual redshifts."""
|
9
|
+
|
10
|
+
storage_type = MULTIPLE_OBJECTS_PER_TABLE
|
11
|
+
|
12
|
+
def __init__(self, name: str, lower: float, upper: float, **kwargs):
|
13
|
+
"""
|
14
|
+
Create a tracer corresponding to a single redshift bin.
|
15
|
+
|
16
|
+
:param name: The name of the tracer
|
17
|
+
:param lower: The lower bound of the redshift bin
|
18
|
+
:param upper: The upper bound of the redshift bin
|
19
|
+
"""
|
20
|
+
super().__init__(name, **kwargs)
|
21
|
+
self.lower = lower
|
22
|
+
self.upper = upper
|
23
|
+
|
24
|
+
def __eq__(self, other) -> bool:
|
25
|
+
"""Test for equality. If :python:`other` is not a
|
26
|
+
:python:`BinZTracer`, then it is not equal to :python:`self`.
|
27
|
+
Otherwise, they are equal if names, and the z-range of the bins,
|
28
|
+
are equal."""
|
29
|
+
if not isinstance(other, BinZTracer):
|
30
|
+
return False
|
31
|
+
return (
|
32
|
+
self.name == other.name
|
33
|
+
and self.lower == other.lower
|
34
|
+
and self.upper == other.upper
|
35
|
+
)
|
36
|
+
|
37
|
+
@classmethod
|
38
|
+
def to_table(cls, instance_list):
|
39
|
+
"""Convert a list of BinZTracers to a single astropy table
|
40
|
+
|
41
|
+
This is used when saving data to a file.
|
42
|
+
One table is generated with the information for all the tracers.
|
43
|
+
|
44
|
+
:param instance_list: List of tracer instances
|
45
|
+
:return: List with a single astropy table
|
46
|
+
"""
|
47
|
+
|
48
|
+
names = ["name", "quantity", "lower", "upper"]
|
49
|
+
|
50
|
+
cols = [
|
51
|
+
[obj.name for obj in instance_list],
|
52
|
+
[obj.quantity for obj in instance_list],
|
53
|
+
[obj.lower for obj in instance_list],
|
54
|
+
[obj.upper for obj in instance_list],
|
55
|
+
]
|
56
|
+
|
57
|
+
table = Table(data=cols, names=names)
|
58
|
+
table.meta["SACCTYPE"] = "tracer"
|
59
|
+
table.meta["SACCCLSS"] = cls.type_name
|
60
|
+
table.meta["EXTNAME"] = f"tracer:{cls.type_name}"
|
61
|
+
return table
|
62
|
+
|
63
|
+
@classmethod
|
64
|
+
def from_table(cls, table):
|
65
|
+
"""Convert an astropy table into a dictionary of tracers
|
66
|
+
|
67
|
+
This is used when loading data from a file.
|
68
|
+
One tracer object is created for each "row" in each table.
|
69
|
+
|
70
|
+
:param table_list: List of astropy tables
|
71
|
+
:return: Dictionary of tracers
|
72
|
+
"""
|
73
|
+
tracers = {}
|
74
|
+
|
75
|
+
for row in table:
|
76
|
+
name = row["name"]
|
77
|
+
quantity = row["quantity"]
|
78
|
+
lower = row["lower"]
|
79
|
+
upper = row["upper"]
|
80
|
+
tracers[name] = cls(name, quantity=quantity, lower=lower, upper=upper)
|
81
|
+
return tracers
|
82
|
+
|
83
|
+
class BinLogMTracer(BaseTracer, type_name="bin_logM"): # type: ignore
|
84
|
+
"""A tracer for a single log-mass bin. The tracer shall
|
85
|
+
be used for binned data where we want a desired quantity
|
86
|
+
per interval of log(mass), such that we only need the data
|
87
|
+
for a given interval instead of at individual masses."""
|
88
|
+
storage_type = MULTIPLE_OBJECTS_PER_TABLE
|
89
|
+
|
90
|
+
def __init__(self, name: str, lower: float, upper: float, **kwargs):
|
91
|
+
"""
|
92
|
+
Create a tracer corresponding to a single log-mass bin.
|
93
|
+
|
94
|
+
:param name: The name of the tracer
|
95
|
+
:param lower: The lower bound of the log-mass bin
|
96
|
+
:param upper: The upper bound of the log-mass bin
|
97
|
+
"""
|
98
|
+
super().__init__(name, **kwargs)
|
99
|
+
self.lower = lower
|
100
|
+
self.upper = upper
|
101
|
+
|
102
|
+
def __eq__(self, other) -> bool:
|
103
|
+
"""Test for equality. If :python:`other` is not a
|
104
|
+
:python:`BinLogMTracer`, then it is not equal to :python:`self`.
|
105
|
+
Otherwise, they are equal if names, and the z-range of the bins,
|
106
|
+
are equal."""
|
107
|
+
if not isinstance(other, BinLogMTracer):
|
108
|
+
return False
|
109
|
+
return (
|
110
|
+
self.name == other.name
|
111
|
+
and self.lower == other.lower
|
112
|
+
and self.upper == other.upper
|
113
|
+
)
|
114
|
+
|
115
|
+
@classmethod
|
116
|
+
def to_table(cls, instance_list):
|
117
|
+
"""Convert a list of BinLogMTracers to a single astropy table
|
118
|
+
|
119
|
+
This is used when saving data to a file.
|
120
|
+
One table is generated with the information for all the tracers.
|
121
|
+
|
122
|
+
:param instance_list: List of tracer instances
|
123
|
+
:return: List with a single astropy table
|
124
|
+
"""
|
125
|
+
|
126
|
+
names = ["name", "quantity", "lower", "upper"]
|
127
|
+
|
128
|
+
cols = [
|
129
|
+
[obj.name for obj in instance_list],
|
130
|
+
[obj.quantity for obj in instance_list],
|
131
|
+
[obj.lower for obj in instance_list],
|
132
|
+
[obj.upper for obj in instance_list],
|
133
|
+
]
|
134
|
+
table = Table(data=cols, names=names)
|
135
|
+
table.meta["SACCTYPE"] = "tracer"
|
136
|
+
table.meta["SACCCLSS"] = cls.type_name
|
137
|
+
table.meta["EXTNAME"] = f"tracer:{cls.type_name}"
|
138
|
+
return table
|
139
|
+
|
140
|
+
@classmethod
|
141
|
+
def from_table(cls, table):
|
142
|
+
"""Convert an astropy table into a dictionary of tracers
|
143
|
+
|
144
|
+
This is used when loading data from a file.
|
145
|
+
One tracer object is created for each "row" in each table.
|
146
|
+
|
147
|
+
:param table_list: List of astropy tables
|
148
|
+
:return: Dictionary of tracers
|
149
|
+
"""
|
150
|
+
tracers = {}
|
151
|
+
|
152
|
+
for row in table:
|
153
|
+
name = row["name"]
|
154
|
+
quantity = row["quantity"]
|
155
|
+
lower = row["lower"]
|
156
|
+
upper = row["upper"]
|
157
|
+
tracers[name] = cls(name, quantity=quantity, lower=lower, upper=upper)
|
158
|
+
return tracers
|
159
|
+
|
160
|
+
|
161
|
+
class BinRichnessTracer(BaseTracer, type_name="bin_richness"): # type: ignore
|
162
|
+
"""A tracer for a single richness bin. The tracer shall
|
163
|
+
be used for binned data where we want a desired quantity
|
164
|
+
per interval of log(richness), such that we only need the data
|
165
|
+
for a given interval instead of at individual richness."""
|
166
|
+
storage_type = MULTIPLE_OBJECTS_PER_TABLE
|
167
|
+
|
168
|
+
def __eq__(self, other) -> bool:
|
169
|
+
"""Test for equality. If :python:`other` is not a
|
170
|
+
:python:`BinRichnessTracer`, then it is not equal to :python:`self`.
|
171
|
+
Otherwise, they are equal if names and the richness-range of the
|
172
|
+
bins, are equal."""
|
173
|
+
if not isinstance(other, BinRichnessTracer):
|
174
|
+
return False
|
175
|
+
return (
|
176
|
+
self.name == other.name
|
177
|
+
and self.lower == other.lower
|
178
|
+
and self.upper == other.upper
|
179
|
+
)
|
180
|
+
|
181
|
+
def __init__(self, name: str, lower: float, upper: float, **kwargs):
|
182
|
+
"""
|
183
|
+
Create a tracer corresponding to a single richness bin.
|
184
|
+
|
185
|
+
:param name: The name of the tracer
|
186
|
+
:param lower: The lower bound of the richness bin in log10.
|
187
|
+
:param upper: The upper bound of the richness bin in log10.
|
188
|
+
"""
|
189
|
+
super().__init__(name, **kwargs)
|
190
|
+
self.lower = lower
|
191
|
+
self.upper = upper
|
192
|
+
|
193
|
+
@classmethod
|
194
|
+
def to_table(cls, instance_list):
|
195
|
+
"""Convert a list of BinZTracers to a list of astropy tables
|
196
|
+
|
197
|
+
This is used when saving data to a file.
|
198
|
+
One table is generated with the information for all the tracers.
|
199
|
+
|
200
|
+
:param instance_list: List of tracer instances
|
201
|
+
:return: List with a single astropy table
|
202
|
+
"""
|
203
|
+
names = ["name", "quantity", "lower", "upper"]
|
204
|
+
|
205
|
+
cols = [
|
206
|
+
[obj.name for obj in instance_list],
|
207
|
+
[obj.quantity for obj in instance_list],
|
208
|
+
[obj.lower for obj in instance_list],
|
209
|
+
[obj.upper for obj in instance_list],
|
210
|
+
]
|
211
|
+
|
212
|
+
table = Table(data=cols, names=names)
|
213
|
+
table.meta["SACCTYPE"] = "tracer"
|
214
|
+
table.meta["SACCCLSS"] = cls.type_name
|
215
|
+
table.meta["EXTNAME"] = f"tracer:{cls.type_name}"
|
216
|
+
return table
|
217
|
+
|
218
|
+
@classmethod
|
219
|
+
def from_table(cls, table):
|
220
|
+
"""Convert an astropy table into a dictionary of tracers
|
221
|
+
|
222
|
+
This is used when loading data from a file.
|
223
|
+
One tracer object is created for each "row" in each table.
|
224
|
+
|
225
|
+
:param table_list: List of astropy tables
|
226
|
+
:return: Dictionary of tracers
|
227
|
+
"""
|
228
|
+
tracers = {}
|
229
|
+
|
230
|
+
for row in table:
|
231
|
+
name = row["name"]
|
232
|
+
quantity = row["quantity"]
|
233
|
+
lower = row["lower"]
|
234
|
+
upper = row["upper"]
|
235
|
+
tracers[name] = cls(
|
236
|
+
name,
|
237
|
+
quantity=quantity,
|
238
|
+
lower=lower,
|
239
|
+
upper=upper,
|
240
|
+
)
|
241
|
+
return tracers
|
242
|
+
|
243
|
+
|
244
|
+
class BinRadiusTracer(BaseTracer, type_name="bin_radius"): # type: ignore
|
245
|
+
"""A tracer for a single radial bin, e.g. when dealing with cluster shear profiles.
|
246
|
+
It gives the bin edges and the value of the bin "center". The latter would typically
|
247
|
+
be returned by CLMM and correspond to the average radius of the galaxies in that
|
248
|
+
radial bin. """
|
249
|
+
|
250
|
+
storage_type = MULTIPLE_OBJECTS_PER_TABLE
|
251
|
+
|
252
|
+
def __eq__(self, other) -> bool:
|
253
|
+
"""Test for equality. If :python:`other` is not a
|
254
|
+
:python:`BinRadiusTracer`, then it is not equal to :python:`self`.
|
255
|
+
Otherwise, they are equal if names and the r-range and centers of the
|
256
|
+
bins, are equal."""
|
257
|
+
if not isinstance(other, BinRadiusTracer):
|
258
|
+
return False
|
259
|
+
return (
|
260
|
+
self.name == other.name
|
261
|
+
and self.lower == other.lower
|
262
|
+
and self.center == other.center
|
263
|
+
and self.upper == other.upper
|
264
|
+
)
|
265
|
+
|
266
|
+
def __init__(self, name: str, lower: float, upper: float, center: float, **kwargs):
|
267
|
+
"""
|
268
|
+
Create a tracer corresponding to a single radial bin.
|
269
|
+
|
270
|
+
:param name: The name of the tracer
|
271
|
+
:param lower: The lower bound of the radius bin
|
272
|
+
:param upper: The upper bound of the radius bin
|
273
|
+
:param center: The value to use if a single point-estimate is needed.
|
274
|
+
|
275
|
+
Note that :python:`center` need not be the midpoint between
|
276
|
+
:python:`lower` and :python:`upper`'.
|
277
|
+
"""
|
278
|
+
super().__init__(name, **kwargs)
|
279
|
+
self.lower = lower
|
280
|
+
self.upper = upper
|
281
|
+
self.center = center
|
282
|
+
|
283
|
+
@classmethod
|
284
|
+
def to_table(cls, instance_list):
|
285
|
+
"""Convert a list of BinRadiusTracers to a single astropy table
|
286
|
+
|
287
|
+
This is used when saving data to a file.
|
288
|
+
One table is generated with the information for all the tracers.
|
289
|
+
|
290
|
+
:param instance_list: List of tracer instances
|
291
|
+
:return: List with a single astropy table
|
292
|
+
"""
|
293
|
+
|
294
|
+
names = ["name", "quantity", "lower", "upper", "center"]
|
295
|
+
|
296
|
+
cols = [
|
297
|
+
[obj.name for obj in instance_list],
|
298
|
+
[obj.quantity for obj in instance_list],
|
299
|
+
[obj.lower for obj in instance_list],
|
300
|
+
[obj.upper for obj in instance_list],
|
301
|
+
[obj.center for obj in instance_list],
|
302
|
+
]
|
303
|
+
|
304
|
+
table = Table(data=cols, names=names)
|
305
|
+
return table
|
306
|
+
|
307
|
+
@classmethod
|
308
|
+
def from_table(cls, table):
|
309
|
+
"""Convert an astropy table into a dictionary of tracers
|
310
|
+
|
311
|
+
This is used when loading data from a file.
|
312
|
+
One tracer object is created for each "row" in each table.
|
313
|
+
|
314
|
+
:param table_list: List of astropy tables
|
315
|
+
:return: Dictionary of tracers
|
316
|
+
"""
|
317
|
+
tracers = {}
|
318
|
+
|
319
|
+
for row in table:
|
320
|
+
name = row["name"]
|
321
|
+
quantity = row["quantity"]
|
322
|
+
lower = row["lower"]
|
323
|
+
upper = row["upper"]
|
324
|
+
center = row["center"]
|
325
|
+
tracers[name] = cls(
|
326
|
+
name,
|
327
|
+
quantity=quantity,
|
328
|
+
lower=lower,
|
329
|
+
upper=upper,
|
330
|
+
center=center,
|
331
|
+
)
|
332
|
+
return tracers
|
sacc/tracers/maps.py
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
from .base import BaseTracer, ONE_OBJECT_PER_TABLE, ONE_OBJECT_MULTIPLE_TABLES
|
2
|
+
from ..utils import remove_dict_null_values
|
3
|
+
from astropy.table import Table
|
4
|
+
import numpy as np
|
5
|
+
|
6
|
+
class MapTracer(BaseTracer, type_name='Map'):
|
7
|
+
"""
|
8
|
+
A Tracer type for a sky map.
|
9
|
+
|
10
|
+
Takes at least two arguments, defining the map beam.
|
11
|
+
|
12
|
+
Parameters
|
13
|
+
----------
|
14
|
+
name: str
|
15
|
+
The name for this specific tracer object.
|
16
|
+
ell: array
|
17
|
+
Array of multipole values at which the beam is defined.
|
18
|
+
beam: array
|
19
|
+
Beam multipoles at each value of ell.
|
20
|
+
beam_extra: array
|
21
|
+
Other beam-related arrays
|
22
|
+
(e.g. uncertainties, principal components,
|
23
|
+
alternative measurements, whatever).
|
24
|
+
map_unit: str
|
25
|
+
Map units (e.g. 'uK_CMB'). 'none' by default.
|
26
|
+
"""
|
27
|
+
|
28
|
+
storage_type = ONE_OBJECT_PER_TABLE
|
29
|
+
|
30
|
+
def __init__(self, name, spin, ell, beam,
|
31
|
+
beam_extra=None, map_unit='none', **kwargs):
|
32
|
+
super().__init__(name, **kwargs)
|
33
|
+
self.spin = spin
|
34
|
+
self.map_unit = map_unit
|
35
|
+
self.ell = np.array(ell)
|
36
|
+
self.beam = np.array(beam)
|
37
|
+
self.beam_extra = {} if beam_extra is None else beam_extra
|
38
|
+
|
39
|
+
def to_table(self):
|
40
|
+
# Beams
|
41
|
+
names = ['ell', 'beam']
|
42
|
+
cols = [self.ell, self.beam]
|
43
|
+
for beam_id, col in self.beam_extra.items():
|
44
|
+
names.append(str(beam_id))
|
45
|
+
cols.append(col)
|
46
|
+
table = Table(data=cols, names=names)
|
47
|
+
table.meta['SACCQTTY'] = self.quantity
|
48
|
+
table.meta['SACCNAME'] = self.name
|
49
|
+
extname = f'tracer:{self.type_name}:{self.name}:beam'
|
50
|
+
table.meta['EXTNAME'] = extname
|
51
|
+
table.meta['MAP_UNIT'] = self.map_unit
|
52
|
+
table.meta['SPIN'] = self.spin
|
53
|
+
for key, value in self.metadata.items():
|
54
|
+
table.meta['META_'+key] = value
|
55
|
+
remove_dict_null_values(table.meta)
|
56
|
+
|
57
|
+
return table
|
58
|
+
|
59
|
+
|
60
|
+
@classmethod
|
61
|
+
def from_table(cls, table):
|
62
|
+
"""Convert a single astropy table into a MapTracer instance.
|
63
|
+
|
64
|
+
This is used when loading data from a file.
|
65
|
+
|
66
|
+
Parameters
|
67
|
+
----------
|
68
|
+
table: astropy.table.Table
|
69
|
+
|
70
|
+
Returns
|
71
|
+
-------
|
72
|
+
tracer: MapTracer
|
73
|
+
An instance of MapTracer created from the table.
|
74
|
+
"""
|
75
|
+
name = table.meta['SACCNAME']
|
76
|
+
quantity = table.meta.get('SACCQTTY', 'generic')
|
77
|
+
map_unit = table.meta['MAP_UNIT']
|
78
|
+
spin = table.meta['SPIN']
|
79
|
+
metadata = {key[5:]: value for key, value in table.meta.items() if key.startswith("META_")}
|
80
|
+
|
81
|
+
ell = table['ell']
|
82
|
+
beam = table['beam']
|
83
|
+
beam_extra = {col.name: col.data for col in table.columns.values() if col.name not in ['ell', 'beam']}
|
84
|
+
|
85
|
+
return cls(name, spin, ell, beam, beam_extra=beam_extra, map_unit=map_unit, quantity=quantity, metadata=metadata)
|
86
|
+
|
87
|
+
|
88
|
+
class NuMapTracer(BaseTracer, type_name='NuMap'):
|
89
|
+
"""
|
90
|
+
A Tracer type for a sky map at a given frequency.
|
91
|
+
|
92
|
+
Takes at least four arguments, defining the bandpass and beam.
|
93
|
+
|
94
|
+
Parameters
|
95
|
+
----------
|
96
|
+
name: str
|
97
|
+
The name for this specific tracer, e.g. a frequency band
|
98
|
+
identifier.
|
99
|
+
spin: int
|
100
|
+
Spin for this observable. Either 0 (e.g. intensity)
|
101
|
+
or 2 (e.g. polarization).
|
102
|
+
nu: array
|
103
|
+
Array of frequencies.
|
104
|
+
bandpass: array
|
105
|
+
Bandpass transmission.
|
106
|
+
bandpass_extra: array
|
107
|
+
Other bandpass-related arrays
|
108
|
+
(e.g. uncertainties, principal components,
|
109
|
+
alternative measurements, whatever).
|
110
|
+
ell: array
|
111
|
+
Array of multipole values at which the beam is defined.
|
112
|
+
beam: array
|
113
|
+
Beam.
|
114
|
+
beam_extra: array
|
115
|
+
Other beam-related arrays
|
116
|
+
(e.g. uncertainties, principal components,
|
117
|
+
alternative measurements, whatever).
|
118
|
+
nu_unit: str
|
119
|
+
Frequency units ('GHz' by default).
|
120
|
+
map_unit: str
|
121
|
+
Map units (e.g. 'uK_CMB'). 'none' by default.
|
122
|
+
"""
|
123
|
+
|
124
|
+
storage_type = ONE_OBJECT_MULTIPLE_TABLES
|
125
|
+
|
126
|
+
def __init__(self, name, spin, nu, bandpass,
|
127
|
+
ell, beam, bandpass_extra=None,
|
128
|
+
beam_extra=None, nu_unit='GHz',
|
129
|
+
map_unit='none', **kwargs):
|
130
|
+
super().__init__(name, **kwargs)
|
131
|
+
self.spin = spin
|
132
|
+
self.nu = np.array(nu)
|
133
|
+
self.nu_unit = nu_unit
|
134
|
+
self.map_unit = map_unit
|
135
|
+
self.bandpass = np.array(bandpass)
|
136
|
+
self.bandpass_extra = {} if bandpass_extra is None else bandpass_extra
|
137
|
+
self.ell = np.array(ell)
|
138
|
+
self.beam = np.array(beam)
|
139
|
+
self.beam_extra = {} if beam_extra is None else beam_extra
|
140
|
+
|
141
|
+
def to_tables(self):
|
142
|
+
# Bandpass
|
143
|
+
names = ['nu', 'bandpass']
|
144
|
+
cols = [self.nu, self.bandpass]
|
145
|
+
for bandpass_id, col in self.bandpass_extra.items():
|
146
|
+
names.append(str(bandpass_id))
|
147
|
+
cols.append(col)
|
148
|
+
bandpass_table = Table(data=cols, names=names)
|
149
|
+
bandpass_table.meta['SACCQTTY'] = self.quantity
|
150
|
+
bandpass_table.meta['NU_UNIT'] = self.nu_unit
|
151
|
+
bandpass_table.meta['SACCNAME'] = self.name
|
152
|
+
bandpass_table.meta['SPIN'] = self.spin
|
153
|
+
for key, value in self.metadata.items():
|
154
|
+
bandpass_table.meta['META_'+key] = value
|
155
|
+
remove_dict_null_values(bandpass_table.meta)
|
156
|
+
|
157
|
+
# Beam
|
158
|
+
names = ['ell', 'beam']
|
159
|
+
cols = [self.ell, self.beam]
|
160
|
+
for beam_id, col in self.beam_extra.items():
|
161
|
+
names.append(str(beam_id))
|
162
|
+
cols.append(col)
|
163
|
+
beam_table = Table(data=cols, names=names)
|
164
|
+
beam_table.meta['SACCQTTY'] = self.quantity
|
165
|
+
beam_table.meta['MAP_UNIT'] = self.map_unit
|
166
|
+
beam_table.meta['SPIN'] = self.spin
|
167
|
+
for key, value in self.metadata.items():
|
168
|
+
beam_table.meta['META_'+key] = value
|
169
|
+
remove_dict_null_values(beam_table.meta)
|
170
|
+
|
171
|
+
return {'bandpass': bandpass_table, 'beam': beam_table}
|
172
|
+
|
173
|
+
@classmethod
|
174
|
+
def from_tables(cls, table_dict):
|
175
|
+
"""Convert a dictionary of astropy tables into a NuMapTracer instance."""
|
176
|
+
bandpass_table = table_dict['bandpass']
|
177
|
+
beam_table = table_dict['beam']
|
178
|
+
|
179
|
+
# Get the various bits of metadata out of the bandpass table
|
180
|
+
name = bandpass_table.meta['SACCNAME']
|
181
|
+
spin = bandpass_table.meta['SPIN']
|
182
|
+
quantity = bandpass_table.meta.get('SACCQTTY', 'generic')
|
183
|
+
nu_unit = bandpass_table.meta['NU_UNIT']
|
184
|
+
|
185
|
+
# Additional miscellaneous metadata
|
186
|
+
metadata = {key[5:]: value for key, value in bandpass_table.meta.items() if key.startswith("META_")}
|
187
|
+
|
188
|
+
# And the actual bandpass data columns themselves
|
189
|
+
nu = bandpass_table['nu']
|
190
|
+
bandpass = bandpass_table['bandpass']
|
191
|
+
bandpass_extra = {col.name: col.data for col in bandpass_table.columns.values() if col.name not in ['nu', 'bandpass']}
|
192
|
+
|
193
|
+
# Now the same for the beam table
|
194
|
+
ell = beam_table['ell']
|
195
|
+
beam = beam_table['beam']
|
196
|
+
beam_extra = {col.name: col.data for col in beam_table.columns.values() if col.name not in ['ell', 'beam']}
|
197
|
+
map_unit = beam_table.meta['MAP_UNIT']
|
198
|
+
|
199
|
+
return cls(name, spin, nu, bandpass,
|
200
|
+
ell, beam,
|
201
|
+
bandpass_extra=bandpass_extra,
|
202
|
+
beam_extra=beam_extra,
|
203
|
+
nu_unit=nu_unit,
|
204
|
+
map_unit=map_unit,
|
205
|
+
quantity=quantity,
|
206
|
+
metadata=metadata)
|
sacc/tracers/misc.py
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
from .base import BaseTracer, MULTIPLE_OBJECTS_PER_TABLE
|
2
|
+
from astropy.table import Table
|
3
|
+
from ..utils import hide_null_values, remove_dict_null_values
|
4
|
+
|
5
|
+
class MiscTracer(BaseTracer, type_name='Misc'):
|
6
|
+
"""A Tracer type for miscellaneous other data points.
|
7
|
+
|
8
|
+
MiscTracers do not have any attributes except for their
|
9
|
+
name, so can be used for tagging external data, for example.
|
10
|
+
|
11
|
+
Parameters
|
12
|
+
----------
|
13
|
+
name: str
|
14
|
+
The name of the tracer
|
15
|
+
"""
|
16
|
+
storage_type = MULTIPLE_OBJECTS_PER_TABLE
|
17
|
+
|
18
|
+
def __init__(self, name, **kwargs):
|
19
|
+
super().__init__(name, **kwargs)
|
20
|
+
|
21
|
+
@classmethod
|
22
|
+
def to_table(cls, instance_list):
|
23
|
+
"""Convert a list of MiscTracer instances to a astropy tables.
|
24
|
+
|
25
|
+
This is used when saving data to file.
|
26
|
+
|
27
|
+
All the instances are converted to a single table, which is
|
28
|
+
returned in a list with one element so that it can be used
|
29
|
+
in combination with the parent.
|
30
|
+
|
31
|
+
You can use the parent class to_tables class method to convert
|
32
|
+
a mixed list of different tracer types.
|
33
|
+
|
34
|
+
You shouldn't generally need to call this method directly.
|
35
|
+
|
36
|
+
Parameters
|
37
|
+
----------
|
38
|
+
instance_list: list
|
39
|
+
list of MiscTracer objects
|
40
|
+
|
41
|
+
Returns
|
42
|
+
-------
|
43
|
+
tables: list
|
44
|
+
List containing one astropy table
|
45
|
+
"""
|
46
|
+
metadata_cols = set()
|
47
|
+
for obj in instance_list:
|
48
|
+
metadata_cols.update(obj.metadata.keys())
|
49
|
+
metadata_cols = list(metadata_cols)
|
50
|
+
|
51
|
+
cols = [[obj.name for obj in instance_list],
|
52
|
+
[obj.quantity for obj in instance_list]]
|
53
|
+
for name in metadata_cols:
|
54
|
+
cols.append([obj.metadata.get(name) for obj in instance_list])
|
55
|
+
|
56
|
+
table = Table(data=cols,
|
57
|
+
names=['name', 'quantity'] + metadata_cols)
|
58
|
+
hide_null_values(table)
|
59
|
+
return table
|
60
|
+
|
61
|
+
@classmethod
|
62
|
+
def from_table(cls, table):
|
63
|
+
"""Convert a list of astropy table into a dictionary of MiscTracer instances.
|
64
|
+
|
65
|
+
In general table_list should have a single element in, since all the
|
66
|
+
MiscTracers are stored in a single table during to_tables
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
table_list: List[astropy.table.Table]
|
71
|
+
|
72
|
+
Returns
|
73
|
+
-------
|
74
|
+
tracers: Dict[str: MiscTracer]
|
75
|
+
"""
|
76
|
+
tracers = {}
|
77
|
+
|
78
|
+
metadata_cols = [col for col in table.colnames
|
79
|
+
if col not in ['name', 'quantity']]
|
80
|
+
|
81
|
+
for row in table:
|
82
|
+
name = row['name']
|
83
|
+
quantity = row['quantity']
|
84
|
+
metadata = {key: row[key] for key in metadata_cols}
|
85
|
+
remove_dict_null_values(metadata)
|
86
|
+
tracers[name] = cls(name, quantity=quantity, metadata=metadata)
|
87
|
+
return tracers
|