Coverage for python/lsst/faro/utils/tex_table.py: 22%
165 statements
« prev ^ index » next coverage.py v6.4.4, created at 2022-09-03 09:32 +0000
« prev ^ index » next coverage.py v6.4.4, created at 2022-09-03 09:32 +0000
1# This file is part of faro.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import astropy.units as u
23import numpy as np
24import treecorr
27__all__ = (
28 "TraceSize",
29 "PsfTraceSizeDiff",
30 "E1",
31 "E2",
32 "E1Resids",
33 "E2Resids",
34 "RhoStatistics",
35 "corrSpin0",
36 "corrSpin2",
37 "calculateTEx",
38)
41class TraceSize(object):
42 """Functor to calculate trace radius size for sources. ixxColumn and
43 iyyColumn are strings and must be defined in the Task Config.
44 """
46 def __init__(self, ixxColumn, iyyColumn):
47 self.ixxColumn = ixxColumn
48 self.iyyColumn = iyyColumn
50 def __call__(self, catalog):
51 srcSize = np.sqrt(0.5 * (catalog[self.ixxColumn] + catalog[self.iyyColumn]))
52 return np.array(srcSize)
55class PsfTraceSizeDiff(object):
56 """Functor to calculate trace radius size difference (%) between object and
57 PSF model. Inherits from functor TraceSize.
58 """
60 def __init__(self, ixxColumn, iyyColumn, ixxPsfColumn, iyyPsfColumn):
61 self.ixxColumn = ixxColumn
62 self.iyyColumn = iyyColumn
63 self.ixxPsfColumn = ixxPsfColumn
64 self.iyyPsfColumn = iyyPsfColumn
66 self.traceSizeFunc = TraceSize(self.ixxColumn, self.iyyColumn)
67 self.psfTraceSizeFunc = TraceSize(self.ixxPsfColumn, self.iyyPsfColumn)
69 def __call__(self, catalog):
70 srcSize = self.traceSizeFunc(catalog)
71 psfSize = self.psfTraceSizeFunc(catalog)
72 sizeDiff = 100 * (srcSize - psfSize) / (0.5 * (srcSize + psfSize))
73 return np.array(sizeDiff)
76class E1(object):
77 """Function to calculate e1 ellipticities from a given catalog.
78 Parameters
79 ----------
80 ixxColumn : `str`
81 The name of the for corresponding ixx ellipticities column.
82 iyyColumn : `str`
83 The name of the for corresponding iyy ellipticities column.
84 ixyColumn : `str`
85 The name of the for corresponding ixy ellipticities column.
86 unitScale : `float`, optional
87 A numerical scaling factor to multiply the ellipticity.
88 shearConvention: `bool`, optional
89 Option to use shear convention. When set to False, the distortion
90 convention is used.
91 Returns
92 -------
93 e1 : `numpy.array`
94 A numpy array of e1 ellipticity values.
95 """
97 def __init__(
98 self, ixxColumn, iyyColumn, ixyColumn, unitScale=1.0, shearConvention=False
99 ):
100 self.ixxColumn = ixxColumn
101 self.iyyColumn = iyyColumn
102 self.ixyColumn = ixyColumn
103 self.unitScale = unitScale
104 self.shearConvention = shearConvention
106 def __call__(self, catalog):
107 xx = catalog[self.ixxColumn]
108 yy = catalog[self.iyyColumn]
109 if self.shearConvention:
110 xy = catalog[self.ixyColumn]
111 e1 = (xx - yy) / (xx + yy + 2.0 * np.sqrt(xx * yy - xy ** 2))
112 else:
113 e1 = (xx - yy) / (xx + yy)
114 return np.array(e1) * self.unitScale
117class E2(object):
118 """Function to calculate e2 ellipticities from a given catalog.
119 Parameters
120 ----------
121 ixxColumn : `str`
122 The name of the for corresponding ixx ellipticities column.
123 iyyColumn : `str`
124 The name of the for corresponding iyy ellipticities column.
125 ixyColumn : `str`
126 The name of the for corresponding ixy ellipticities column.
127 unitScale : `float`, optional
128 A numerical scaling factor to multiply the ellipticity.
129 shearConvention: `bool`, optional
130 Option to use shear convention. When set to False, the distortion
131 convention is used.
132 Returns
133 -------
134 e2 : `numpy.array`
135 A numpy array of e2 ellipticity values.
136 """
138 def __init__(
139 self, ixxColumn, iyyColumn, ixyColumn, unitScale=1.0, shearConvention=False
140 ):
141 self.ixxColumn = ixxColumn
142 self.iyyColumn = iyyColumn
143 self.ixyColumn = ixyColumn
144 self.unitScale = unitScale
145 self.shearConvention = shearConvention
147 def __call__(self, catalog):
148 xx = catalog[self.ixxColumn]
149 yy = catalog[self.iyyColumn]
150 xy = catalog[self.ixyColumn]
151 if self.shearConvention:
152 e2 = (2.0 * xy) / (xx + yy + 2.0 * np.sqrt(xx * yy - xy ** 2))
153 else:
154 e2 = (2.0 * xy) / (xx + yy)
155 return np.array(e2) * self.unitScale
158class E1Resids(object):
159 """Functor to calculate e1 ellipticity residuals from an object catalog
160 and PSF model.
161 Parameters
162 ----------
163 ixxColumn : `str`
164 The name of the for corresponding ixx ellipticities column.
165 iyyColumn : `str`
166 The name of the for corresponding iyy ellipticities column.
167 ixyColumn : `str`
168 The name of the for corresponding ixy ellipticities column.
169 ixxPsfColumn : `str`
170 The name of the for corresponding ixx psf ellipticities column.
171 iyyPsfColumn : `str`
172 The name of the for corresponding iyy psf ellipticities column.
173 ixyPsfColumn : `str`
174 The name of the for corresponding ixy psf ellipticities column.
175 unitScale : `float`, optional
176 A numerical scaling factor to multiply both the object and PSF
177 ellipticities.
178 shearConvention: `bool`, optional
179 Option to use shear convention. When set to False, the distortion
180 convention is used.
181 Returns
182 -------
183 e1Resids : `numpy.array`
184 A numpy array of e1 residual ellipticity values.
185 """
187 def __init__(
188 self,
189 ixxColumn,
190 iyyColumn,
191 ixxPsfColumn,
192 iyyPsfColumn,
193 ixyColumn,
194 ixyPsfColumn,
195 unitScale=1.0,
196 shearConvention=False,
197 ):
198 self.ixxColumn = ixxColumn
199 self.iyyColumn = iyyColumn
200 self.ixyColumn = ixyColumn
201 self.ixxPsfColumn = ixxPsfColumn
202 self.iyyPsfColumn = iyyPsfColumn
203 self.ixyPsfColumn = ixyPsfColumn
205 self.unitScale = unitScale
206 self.shearConvention = shearConvention
208 def __call__(self, catalog):
209 srcE1func = E1(
210 self.ixxColumn,
211 self.iyyColumn,
212 self.ixyColumn,
213 self.unitScale,
214 self.shearConvention,
215 )
216 psfE1func = E1(
217 self.ixxPsfColumn,
218 self.iyyPsfColumn,
219 self.ixyPsfColumn,
220 self.unitScale,
221 self.shearConvention,
222 )
224 srcE1 = srcE1func(catalog)
225 psfE1 = psfE1func(catalog)
227 e1Resids = srcE1 - psfE1
228 return e1Resids
231class E2Resids(object):
232 """Functor to calculate e2 ellipticity residuals from an object catalog
233 and PSF model.
234 Parameters
235 ----------
236 ixxColumn : `str`
237 The name of the for corresponding ixx ellipticities column.
238 iyyColumn : `str`
239 The name of the for corresponding iyy ellipticities column.
240 ixyColumn : `str`
241 The name of the for corresponding ixy ellipticities column.
242 ixxPsfColumn : `str`
243 The name of the for corresponding ixx psf ellipticities column.
244 iyyPsfColumn : `str`
245 The name of the for corresponding iyy psf ellipticities column.
246 ixyPsfColumn : `str`
247 The name of the for corresponding ixy psf ellipticities column.
248 unitScale : `float`, optional
249 A numerical scaling factor to multiply both the object and PSF
250 ellipticities.
251 shearConvention: `bool`, optional
252 Option to use shear convention. When set to False, the distortion
253 convention is used.
254 Returns
255 -------
256 e2Resids : `numpy.array`
257 A numpy array of e2 residual ellipticity values.
258 """
260 def __init__(
261 self,
262 ixxColumn,
263 iyyColumn,
264 ixxPsfColumn,
265 iyyPsfColumn,
266 ixyColumn,
267 ixyPsfColumn,
268 unitScale=1.0,
269 shearConvention=False,
270 ):
271 self.ixxColumn = ixxColumn
272 self.iyyColumn = iyyColumn
273 self.ixyColumn = ixyColumn
274 self.ixxPsfColumn = ixxPsfColumn
275 self.iyyPsfColumn = iyyPsfColumn
276 self.ixyPsfColumn = ixyPsfColumn
277 self.unitScale = unitScale
278 self.shearConvention = shearConvention
280 def __call__(self, catalog):
281 srcE2func = E2(
282 self.ixxColumn,
283 self.iyyColumn,
284 self.ixyColumn,
285 self.unitScale,
286 self.shearConvention,
287 )
288 psfE2func = E2(
289 self.ixxPsfColumn,
290 self.iyyPsfColumn,
291 self.ixyPsfColumn,
292 self.unitScale,
293 self.shearConvention,
294 )
296 srcE2 = srcE2func(catalog)
297 psfE2 = psfE2func(catalog)
299 e2Resids = srcE2 - psfE2
300 return e2Resids
303class RhoStatistics(object):
304 """Functor to compute Rho statistics given star catalog and PSF model.
305 For detailed description of Rho statistics, refer to
306 Rowe (2010) and Jarvis et al., (2016).
307 Parameters
308 ----------
309 column : `str`
310 The name of the shape measurement algorithm. It should be one of
311 ("base_SdssShape", "ext_shapeHSM_HsmSourceMoments").
312 psfColumn : `str`
313 The name used for PSF shape measurements from the same algorithm.
314 It must be one of ("base_SdssShape_psf", "ext_shapeHSM_HsmPsfMoments")
315 and correspond to the algorithm name specified for ``column``.
316 shearConvention: `bool`, optional
317 Option to use shear convention. When set to False, the distortion
318 convention is used.
319 **kwargs
320 Additional keyword arguments passed to treecorr. See
321 https://rmjarvis.github.io/TreeCorr/_build/html/gg.html for details.
322 Returns
323 -------
324 rhoStats : `dict` [`int`, `treecorr.KKCorrelation` or
325 `treecorr.GGCorrelation`]
326 A dictionary with keys 0..5, containing one `treecorr.KKCorrelation`
327 object (key 0) and five `treecorr.GGCorrelation` objects corresponding
328 to Rho statistic indices. rho0 corresponds to autocorrelation function
329 of PSF size residuals.
330 """
332 def __init__(
333 self,
334 ixxColumn,
335 iyyColumn,
336 ixxPsfColumn,
337 iyyPsfColumn,
338 raColumn,
339 decColumn,
340 ixyColumn,
341 ixyPsfColumn,
342 shearConvention=False,
343 **kwargs
344 ):
345 self.ixxColumn = ixxColumn
346 self.iyyColumn = iyyColumn
347 self.ixyColumn = ixyColumn
348 self.ixxPsfColumn = ixxPsfColumn
349 self.iyyPsfColumn = iyyPsfColumn
350 self.ixyPsfColumn = ixyPsfColumn
351 self.shearConvention = shearConvention
352 self.raColumn = raColumn
353 self.decColumn = decColumn
354 self.e1Func = E1(
355 self.ixxPsfColumn,
356 self.iyyPsfColumn,
357 self.ixyPsfColumn,
358 shearConvention=self.shearConvention,
359 )
360 self.e2Func = E2(
361 self.ixxPsfColumn,
362 self.iyyPsfColumn,
363 self.ixyPsfColumn,
364 shearConvention=self.shearConvention,
365 )
366 self.e1ResidsFunc = E1Resids(
367 self.ixxColumn,
368 self.iyyColumn,
369 self.ixxPsfColumn,
370 self.iyyPsfColumn,
371 self.ixyColumn,
372 self.ixyPsfColumn,
373 shearConvention=self.shearConvention,
374 )
375 self.e2ResidsFunc = E2Resids(
376 self.ixxColumn,
377 self.iyyColumn,
378 self.ixxPsfColumn,
379 self.iyyPsfColumn,
380 self.ixyColumn,
381 self.ixyPsfColumn,
382 shearConvention=self.shearConvention,
383 )
384 self.traceSizeFunc = TraceSize(self.ixxColumn, self.iyyColumn)
385 self.psfTraceSizeFunc = TraceSize(self.ixxPsfColumn, self.iyyPsfColumn)
386 self.kwargs = kwargs
388 def __call__(self, catalog):
389 e1 = self.e1Func(catalog)
390 e2 = self.e2Func(catalog)
391 e1Res = self.e1ResidsFunc(catalog)
392 e2Res = self.e2ResidsFunc(catalog)
393 traceSize2 = self.traceSizeFunc(catalog) ** 2
394 psfTraceSize2 = self.psfTraceSizeFunc(catalog) ** 2
395 SizeRes = (traceSize2 - psfTraceSize2) / (0.5 * (traceSize2 + psfTraceSize2))
397 isFinite = np.isfinite(e1Res) & np.isfinite(e2Res) & np.isfinite(SizeRes)
398 e1 = e1[isFinite]
399 e2 = e2[isFinite]
400 e1Res = e1Res[isFinite]
401 e2Res = e2Res[isFinite]
402 SizeRes = SizeRes[isFinite]
404 # Scale the SizeRes by ellipticities
405 e1SizeRes = e1 * SizeRes
406 e2SizeRes = e2 * SizeRes
408 # Package the arguments to capture auto-/cross-correlations for the
409 # Rho statistics.
410 args = {
411 0: (SizeRes, None),
412 1: (e1Res, e2Res, None, None),
413 2: (e1, e2, e1Res, e2Res),
414 3: (e1SizeRes, e2SizeRes, None, None),
415 4: (e1Res, e2Res, e1SizeRes, e2SizeRes),
416 5: (e1, e2, e1SizeRes, e2SizeRes),
417 }
419 ra = catalog[self.raColumn][isFinite] * 60.0 # arcmin
420 dec = catalog[self.decColumn][isFinite] * 60.0 # arcmin
422 # Pass the appropriate arguments to the correlator and build a dict
423 rhoStats = {
424 rhoIndex: corrSpin2(
425 ra,
426 dec,
427 *(args[rhoIndex]),
428 raUnits="arcmin",
429 decUnits="arcmin",
430 **self.kwargs
431 )
432 for rhoIndex in range(1, 6)
433 }
434 rhoStats[0] = corrSpin0(
435 ra, dec, *(args[0]), raUnits="arcmin", decUnits="arcmin", **self.kwargs
436 )
438 return rhoStats
441def corrSpin0(
442 ra, dec, k1, k2=None, raUnits="degrees", decUnits="degrees", **treecorrKwargs
443):
444 """Function to compute correlations between at most two scalar fields.
445 This is used to compute Rho0 statistics, given the appropriate spin-0
446 (scalar) fields, usually fractional size residuals.
447 Parameters
448 ----------
449 ra : `numpy.array`
450 The right ascension values of entries in the catalog.
451 dec : `numpy.array`
452 The declination values of entries in the catalog.
453 k1 : `numpy.array`
454 The primary scalar field.
455 k2 : `numpy.array`, optional
456 The secondary scalar field.
457 Autocorrelation of the primary field is computed if `None` (default).
458 raUnits : `str`, optional
459 Unit of the right ascension values.
460 Valid options are "degrees", "arcmin", "arcsec", "hours" or "radians".
461 decUnits : `str`, optional
462 Unit of the declination values.
463 Valid options are "degrees", "arcmin", "arcsec", "hours" or "radians".
464 **treecorrKwargs
465 Keyword arguments to be passed to `treecorr.KKCorrelation`.
466 Returns
467 -------
468 xy : `treecorr.KKCorrelation`
469 A `treecorr.KKCorrelation` object containing the correlation function.
470 """
472 xy = treecorr.KKCorrelation(**treecorrKwargs)
473 catA = treecorr.Catalog(ra=ra, dec=dec, k=k1, ra_units=raUnits, dec_units=decUnits)
474 if k2 is None:
475 # Calculate the auto-correlation
476 xy.process(catA)
477 else:
478 catB = treecorr.Catalog(
479 ra=ra, dec=dec, k=k2, ra_units=raUnits, dec_units=decUnits
480 )
481 # Calculate the cross-correlation
482 xy.process(catA, catB)
484 return xy
487def corrSpin2(
488 ra,
489 dec,
490 g1a,
491 g2a,
492 g1b=None,
493 g2b=None,
494 raUnits="degrees",
495 decUnits="degrees",
496 **treecorrKwargs
497):
498 """Function to compute correlations between at most two shear-like fields.
499 This is used to compute Rho statistics, given the appropriate spin-2
500 (shear-like) fields.
501 Parameters
502 ----------
503 ra : `numpy.array`
504 The right ascension values of entries in the catalog.
505 dec : `numpy.array`
506 The declination values of entries in the catalog.
507 g1a : `numpy.array`
508 The first component of the primary shear-like field.
509 g2a : `numpy.array`
510 The second component of the primary shear-like field.
511 g1b : `numpy.array`, optional
512 The first component of the secondary shear-like field.
513 Autocorrelation of the primary field is computed if `None` (default).
514 g2b : `numpy.array`, optional
515 The second component of the secondary shear-like field.
516 Autocorrelation of the primary field is computed if `None` (default).
517 raUnits : `str`, optional
518 Unit of the right ascension values.
519 Valid options are "degrees", "arcmin", "arcsec", "hours" or "radians".
520 decUnits : `str`, optional
521 Unit of the declination values.
522 Valid options are "degrees", "arcmin", "arcsec", "hours" or "radians".
523 **treecorrKwargs
524 Keyword arguments to be passed to `treecorr.GGCorrelation`.
525 Returns
526 -------
527 xy : `treecorr.GGCorrelation`
528 A `treecorr.GGCorrelation` object containing the correlation function.
529 """
530 xy = treecorr.GGCorrelation(**treecorrKwargs)
531 catA = treecorr.Catalog(
532 ra=ra, dec=dec, g1=g1a, g2=g2a, ra_units=raUnits, dec_units=decUnits
533 )
534 if g1b is None or g2b is None:
535 # Calculate the auto-correlation
536 xy.process(catA)
537 else:
538 catB = treecorr.Catalog(
539 ra=ra, dec=dec, g1=g1b, g2=g2b, ra_units=raUnits, dec_units=decUnits
540 )
541 # Calculate the cross-correlation
542 xy.process(catA, catB)
544 return xy
547def calculateTEx(catalog, config, currentBand):
548 """Compute ellipticity residual correlation metrics using parquet table as input.
549 Parameters
550 ----------
551 catalog : `pandas datafram`
552 The catalog on which TE values will be calculated.
553 config : `pex config`
554 Task configuration.
555 prependString : `str`
556 The string to prepend to the band-specific columns. Typically a single letter
557 filter e.g. 'g'.
558 Returns
559 -------
560 result : `dict`
561 A dictionary with entries for radius, corr, and corrErr.
562 """
564 ixxColumn = config._getColumnName("ixx", currentBand)
565 iyyColumn = config._getColumnName("iyy", currentBand)
566 ixyColumn = config._getColumnName("ixy", currentBand)
567 ixxPsfColumn = config._getColumnName("ixxPsf", currentBand)
568 iyyPsfColumn = config._getColumnName("ixxPsf", currentBand)
569 ixyPsfColumn = config._getColumnName("ixxPsf", currentBand)
571 nMinSources = 50
572 if len(catalog) < nMinSources:
573 return {"nomeas": np.nan * u.Unit("")}
575 treecorrKwargs = dict(
576 nbins=config.nbins,
577 min_sep=config.minSep,
578 max_sep=config.maxSep,
579 sep_units="arcmin",
580 )
582 rhoStatisticsFunc = RhoStatistics(
583 ixxColumn,
584 iyyColumn,
585 ixxPsfColumn,
586 iyyPsfColumn,
587 config._getColumnName("ra"),
588 config._getColumnName("dec"),
589 ixyColumn,
590 ixyPsfColumn,
591 shearConvention=config.shearConvention,
592 **treecorrKwargs
593 )
594 xy = rhoStatisticsFunc(catalog)[config.rhoStat]
596 radius = np.exp(xy.meanlogr) * u.arcmin
597 if config.rhoStat == 0:
598 corr = xy.xi * u.Unit("")
599 corrErr = np.sqrt(xy.varxip) * u.Unit("")
600 else:
601 corr = xy.xip * u.Unit("")
602 corrErr = np.sqrt(xy.varxip) * u.Unit("")
604 result = dict(radius=radius, corr=corr, corrErr=corrErr)
605 return result