Skip to content

Commit 157bdb0

Browse files
m-aguenahsinfan1996combet
authoredOct 7, 2024··
Issue/401/use qp+fix zinteg (#644)
* implement qp * unify z_grid in integration, use qp for interpolation * add quantiles in mock_data and GCData.get_pzpdfs * lower requirement for quantiles integration * rename pzpdf column to pzquantiles when type is quantiles * update examples/demo_mock_cluster.ipynb * mv pylint to after tests in github * add examples/demo_compute_bkg_probability_details.ipynb * Install qp with pip prereqs, add qp to environment.yml * Update version to 1.14.0 --------- Co-authored-by: Hsin Fan <57552401+hsinfan1996@users.noreply.github.com> Co-authored-by: Celine Combet <celine.combet@lpsc.in2p3.fr>
1 parent 7d90ee1 commit 157bdb0

13 files changed

+677
-121
lines changed
 

‎.github/workflows/build_check.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@ jobs:
3939
git clone https://github.com/LSSTDESC/CCL
4040
cd CCL
4141
pip install --no-use-pep517 .
42-
- name: Analysing the code with pylint
43-
run: |
44-
pip install pylint
45-
pylint clmm --ignored-classes=astropy.units
4642
- name: Run the unit tests
4743
run: |
4844
pip install pytest pytest-cov
@@ -53,6 +49,10 @@ jobs:
5349
# - name: Install Sphinx prereq
5450
# run: |
5551
# conda install -c conda-forge sphinx sphinx_rtd_theme nbconvert pandoc ipython ipython_genutils
52+
- name: Analysing the code with pylint
53+
run: |
54+
pip install pylint
55+
pylint clmm --ignored-classes=astropy.units
5656
- name: Run the docs
5757
run: |
5858
make -C docs/ html

‎INSTALL.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ Note, you may choose to install some or all of the ccl, numcosmo, and/or cluster
5656
Now, you can install CLMM and its dependencies as
5757

5858
```bash
59-
pip install numpy scipy astropy matplotlib
59+
pip install numpy scipy astropy matplotlib healpy
6060
pip install pytest sphinx sphinx_rtd_theme
6161
pip install jupyter # need to have jupyter notebook tied to this environment, you can then see the environment in jupyter.nersc.gov
62+
pip install git+https://github.com/LSSTDESC/qp.git # Install qp package
6263
git clone https://github.com/LSSTDESC/CLMM.git # If you'd like to contribute but don't have edit permissions to the CLMM repo, see below how to fork the repo instead.
6364
cd CLMM
6465
python setup.py install # build from source

‎clmm/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@
2626
)
2727
from . import support
2828

29-
__version__ = "1.13.2"
29+
__version__ = "1.14.0"

‎clmm/gcdata.py

+33-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from astropy.table import Table as APtable
77
import numpy as np
88

9+
import qp
10+
911

1012
class GCMetaData(OrderedDict):
1113
r"""Object to store metadata, it always has a cosmo key with protective changes
@@ -65,7 +67,10 @@ def __init__(self, *args, **kwargs):
6567
metakwargs = {} if metakwargs is None else metakwargs
6668
self.meta = GCMetaData(**metakwargs)
6769
# this attribute is set when source galaxies have p(z)
68-
self.pzpdf_info = {"type": None}
70+
self.pzpdf_info = {
71+
"type": None,
72+
"unpack_quantile_zbins_limits": (0, 5, 501),
73+
}
6974

7075
def _str_colnames(self):
7176
"""Colnames in comma separated str"""
@@ -83,6 +88,12 @@ def _str_pzpdf_info(self):
8388
np.set_printoptions(edgeitems=5, threshold=10)
8489
out += " " + str(np.round(self.pzpdf_info.get("zbins"), 2))
8590
np.set_printoptions(**default_cfg)
91+
elif out == "quantiles":
92+
np.set_printoptions(formatter={'float': "{0:g}".format}, edgeitems=3, threshold=6)
93+
out += " " + str(self.pzpdf_info["quantiles"])
94+
out += " - unpacked with zgrid : " + str(
95+
self.pzpdf_info["unpack_quantile_zbins_limits"]
96+
)
8697
return out
8798

8899
def __repr__(self):
@@ -227,6 +238,8 @@ def has_pzpdfs(self):
227238
return ("zbins" in self.pzpdf_info) and ("pzpdf" in self.columns)
228239
if pzpdf_type == "individual_bins":
229240
return ("pzbins" in self.columns) and ("pzpdf" in self.columns)
241+
if pzpdf_type == "quantiles":
242+
return ("quantiles" in self.pzpdf_info) and ("pzquantiles" in self.columns)
230243
raise NotImplementedError(f"PDF use '{pzpdf_type}' not implemented.")
231244

232245
def get_pzpdfs(self):
@@ -235,18 +248,35 @@ def get_pzpdfs(self):
235248
Returns
236249
-------
237250
pzbins : array
238-
zbins of PDF. 1D if `shared_bins`,
251+
zbins of PDF. 1D if `shared_bins` or `quantiles`.
239252
zbins of each object in data if `individual_bins`.
240253
pzpdfs : array
241254
PDF of each object in data
255+
256+
Notes
257+
-----
258+
If pzpdf type is quantiles, a pdf will be unpacked on a grid contructed with
259+
`np.linspace(*self.pzpdf_info["unpack_quantile_zbins_limits"])`
242260
"""
243261
pzpdf_type = self.pzpdf_info["type"]
244262
if pzpdf_type is None:
245263
raise ValueError("No PDF information stored!")
246264
if pzpdf_type == "shared_bins":
247265
pzbins = self.pzpdf_info["zbins"]
266+
pzpdf = self["pzpdf"]
248267
elif pzpdf_type == "individual_bins":
249268
pzbins = self["pzbins"]
269+
pzpdf = self["pzpdf"]
270+
elif pzpdf_type == "quantiles":
271+
pzbins = np.linspace(*self.pzpdf_info["unpack_quantile_zbins_limits"])
272+
qp_ensemble = qp.Ensemble(
273+
qp.quant,
274+
data={
275+
"quants": np.array(self.pzpdf_info["quantiles"]),
276+
"locs": self["pzquantiles"],
277+
},
278+
)
279+
pzpdf = qp_ensemble.pdf(pzbins)
250280
else:
251281
raise NotImplementedError(f"PDF use '{pzpdf_type}' not implemented.")
252-
return pzbins, self["pzpdf"]
282+
return pzbins, pzpdf

‎clmm/redshift/tools.py

+26-24
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import warnings
33
import numpy as np
44
from scipy.integrate import simpson
5-
from scipy.interpolate import interp1d
65

6+
import qp
77

8-
def _integ_pzfuncs(pzpdf, pzbins, zmin=0.0, zmax=5, kernel=lambda z: 1.0, ngrid=1000):
8+
9+
def _integ_pzfuncs(pzpdf, pzbins, zmin=0.0, zmax=5, kernel=None, ngrid=1000):
910
r"""
1011
Integrates the product of a photo-z pdf with a given kernel.
1112
This function was created to allow for data with different photo-z binnings.
@@ -30,30 +31,31 @@ def _integ_pzfuncs(pzpdf, pzbins, zmin=0.0, zmax=5, kernel=lambda z: 1.0, ngrid=
3031
-------
3132
numpy.ndarray
3233
Kernel integrated with the pdf of each galaxy.
33-
34-
Notes
35-
-----
36-
Will be replaced by qp at some point.
3734
"""
38-
# adding these lines to interpolate CLMM redshift grid for each galaxies
39-
# to a constant redshift grid for all galaxies. If there is a constant grid for all galaxies
40-
# these lines are not necessary and z_grid, pz_matrix = pzbins, pzpdf
41-
42-
if hasattr(pzbins[0], "__len__"):
43-
# First need to interpolate on a fixed grid
44-
z_grid = np.linspace(zmin, zmax, ngrid)
45-
pdf_interp_list = [
46-
interp1d(pzbin, pdf, bounds_error=False, fill_value=0.0)
47-
for pzbin, pdf in zip(pzbins, pzpdf)
48-
]
49-
pz_matrix = np.array([pdf_interp(z_grid) for pdf_interp in pdf_interp_list])
50-
kernel_matrix = kernel(z_grid)
35+
36+
if len(np.array(pzbins).shape) > 1:
37+
# Each galaxy as a diiferent zbin
38+
_qp_type = qp.interp_irregular
5139
else:
52-
# OK perform the integration directly from the pdf binning common to all galaxies
53-
mask = (pzbins >= zmin) * (pzbins <= zmax)
54-
z_grid = pzbins[mask]
55-
pz_matrix = np.array(pzpdf)[:, mask]
56-
kernel_matrix = kernel(z_grid)
40+
_qp_type = qp.interp
41+
42+
qp_ensemble = qp.Ensemble(
43+
_qp_type,
44+
data={
45+
"xvals": np.array(pzbins),
46+
"yvals": np.array(pzpdf),
47+
},
48+
)
49+
50+
if kernel is None:
51+
52+
def kernel(z):
53+
# pylint: disable=unused-argument
54+
return 1.0
55+
56+
z_grid = np.linspace(zmin, zmax, ngrid)
57+
pz_matrix = qp_ensemble.pdf(z_grid)
58+
kernel_matrix = kernel(z_grid)
5759

5860
return simpson(pz_matrix * kernel_matrix, x=z_grid, axis=1)
5961

‎clmm/support/mock_data.py

+27-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import warnings
44
import numpy as np
5+
6+
from scipy.special import erfc
7+
58
from astropy import units as u
69
from astropy.coordinates import SkyCoord
710

@@ -39,6 +42,7 @@ def generate_galaxy_catalog(
3942
ngals=None,
4043
ngal_density=None,
4144
pz_bins=101,
45+
pz_quantiles_conf=(5, 31),
4246
pzpdf_type="shared_bins",
4347
coordinate_system="euclidean",
4448
validate_input=True,
@@ -145,12 +149,16 @@ def generate_galaxy_catalog(
145149
pz_bins: int, array
146150
Photo-z pdf bins in the given range. If int, the limits are set automatically.
147151
If is array, must be the bin edges.
152+
pz_quantiles_conf: tuple
153+
Configuration for quantiles when `pzpdf_type='quantiles'`. Must be with the format
154+
`(max_sigma_dev, num_points)`, which is used as
155+
`sigma_steps = np.linspace(-max_sigma_dev, max_sigma_dev, num_points)`
148156
pzpdf_type: str, None
149157
Type of photo-z pdf to be stored, options are:
150158
`None` - does not store PDFs;
151159
`'shared_bins'` - single binning for all galaxies
152160
`'individual_bins'` - individual binning for each galaxy
153-
`'quantiles'` - quantiles of PDF (not implemented yet)
161+
`'quantiles'` - quantiles of PDF
154162
nretry : int, optional
155163
The number of times that we re-draw each galaxy with non-sensical derived properties
156164
ngals : float, optional
@@ -238,6 +246,7 @@ def generate_galaxy_catalog(
238246
"mean_e_err": mean_e_err,
239247
"photoz_sigma_unscaled": photoz_sigma_unscaled,
240248
"pz_bins": pz_bins,
249+
"pz_quantiles_conf": pz_quantiles_conf,
241250
"field_size": field_size,
242251
"pzpdf_type": pzpdf_type,
243252
"coordinate_system": coordinate_system,
@@ -370,6 +379,7 @@ def _generate_galaxy_catalog(
370379
mean_e_err=None,
371380
photoz_sigma_unscaled=None,
372381
pz_bins=101,
382+
pz_quantiles_conf=(5, 31),
373383
pzpdf_type="shared_bins",
374384
coordinate_system="euclidean",
375385
field_size=None,
@@ -389,7 +399,10 @@ def _generate_galaxy_catalog(
389399
if photoz_sigma_unscaled is not None:
390400
galaxy_catalog.pzpdf_info["type"] = pzpdf_type
391401
galaxy_catalog = _compute_photoz_pdfs(
392-
galaxy_catalog, photoz_sigma_unscaled, pz_bins=pz_bins
402+
galaxy_catalog,
403+
photoz_sigma_unscaled,
404+
pz_bins=pz_bins,
405+
pz_quantiles_conf=pz_quantiles_conf,
393406
)
394407

395408
# Draw galaxy positions
@@ -462,7 +475,10 @@ def _generate_galaxy_catalog(
462475
if all(c is not None for c in (photoz_sigma_unscaled, pzpdf_type)):
463476
if galaxy_catalog.pzpdf_info["type"] == "individual_bins":
464477
cols += ["pzbins"]
465-
cols += ["pzpdf"]
478+
if galaxy_catalog.pzpdf_info["type"] == "quantiles":
479+
cols += ["pzquantiles"]
480+
else:
481+
cols += ["pzpdf"]
466482

467483
if coordinate_system == "celestial":
468484
galaxy_catalog["e2"] *= -1 # flip e2 to match the celestial coordinate system
@@ -529,7 +545,9 @@ def _draw_source_redshifts(zsrc, zsrc_min, zsrc_max, ngals):
529545
return GCData([zsrc_list, zsrc_list], names=("ztrue", "z"))
530546

531547

532-
def _compute_photoz_pdfs(galaxy_catalog, photoz_sigma_unscaled, pz_bins=101):
548+
def _compute_photoz_pdfs(
549+
galaxy_catalog, photoz_sigma_unscaled, pz_bins=101, pz_quantiles_conf=(5, 31)
550+
):
533551
"""Private function to add photo-z errors and PDFs to the mock catalog.
534552
535553
Parameters
@@ -582,7 +600,11 @@ def _compute_photoz_pdfs(galaxy_catalog, photoz_sigma_unscaled, pz_bins=101):
582600
gaussian(row["pzbins"], row["z"], row["pzsigma"]) for row in galaxy_catalog
583601
]
584602
elif galaxy_catalog.pzpdf_info["type"] == "quantiles":
585-
raise NotImplementedError("PDF storing in quantiles not implemented.")
603+
sigma_steps = np.linspace(-pz_quantiles_conf[0], pz_quantiles_conf[0], pz_quantiles_conf[1])
604+
galaxy_catalog.pzpdf_info["quantiles"] = 0.5 * erfc(-sigma_steps / np.sqrt(2))
605+
galaxy_catalog["pzquantiles"] = (
606+
galaxy_catalog["z"][:, None] + sigma_steps * galaxy_catalog["pzsigma"][:, None]
607+
)
586608
else:
587609
raise ValueError(
588610
"Value of pzpdf_info['type'] " f"(={galaxy_catalog.pzpdf_info['type']}) " "not valid."

‎environment.yml

+2
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ dependencies:
1818
- numcosmo==0.18.2
1919
- pytest=7.4.0
2020
- sphinx==7.2.4
21+
- pip:
22+
- qp-prob @ git+https://github.com/LSSTDESC/qp.git

0 commit comments

Comments
 (0)
Please sign in to comment.