# Copyright (c) 2003-2024 by Mike Jarvis
#
# TreeCorr is free software: redistribution and use in source and binary forms,
# with or without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions, and the disclaimer given in the accompanying LICENSE
# file.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the disclaimer given in the documentation
# and/or other materials provided with the distribution.
"""
.. module:: kkkcorrelation
"""
import numpy as np
from . import _treecorr
from .catalog import calculateVarK
from .corr3base import Corr3
[docs]
class KKKCorrelation(Corr3):
r"""This class handles the calculation and storage of a 3-point scalar-scalar-scalar correlation
function.
.. note::
While we use the term kappa (:math:`\kappa`) here and the letter K in various places,
in fact any scalar field will work here. For example, you can use this to compute
correlations of the CMB temperature fluctuations, where "kappa" would really be
:math:`\Delta T`.
See the docstring of `Corr3` for a description of how the triangles are binned along
with the attributes related to the different binning options.
In addition to the attributes common to all `Corr3` subclasses, objects of this class
hold the following attributes:
Attributes:
zeta: The correlation function, :math:`\zeta`.
varzeta: The variance estimate of :math:`\zeta`, computed according to ``var_method``
(default: ``'shot'``).
The typical usage pattern is as follows:
>>> kkk = treecorr.KKKCorrelation(config)
>>> kkk.process(cat) # Compute the auto-correlation.
>>> # kkk.process(cat1, cat2, cat3) # ... or the cross-correlation.
>>> kkk.write(file_name) # Write out to a file.
>>> zeta = kkk.zeta # Access zeta directly.
See also: `KKGCorrelation`, `NKKCorrelation`, `KKCorrelation`.
Parameters:
config (dict): A configuration dict that can be used to pass in kwargs if desired.
This dict is allowed to have additional entries besides those listed
in `Corr3`, which are ignored here. (default: None)
logger (:class:`logging.Logger`):
If desired, a ``Logger`` object for logging. (default: None, in which case
one will be built according to the config dict's verbose level.)
Keyword Arguments:
**kwargs: See the documentation for `Corr3` for the list of allowed keyword
arguments, which may be passed either directly or in the config dict.
"""
_cls = 'KKKCorrelation'
_letter1 = 'K'
_letter2 = 'K'
_letter3 = 'K'
_letters = 'KKK'
_builder = _treecorr.KKKCorr
_calculateVar1 = staticmethod(calculateVarK)
_calculateVar2 = staticmethod(calculateVarK)
_calculateVar3 = staticmethod(calculateVarK)
_sig1 = 'sig_k'
_sig2 = 'sig_k'
_sig3 = 'sig_k'
_default_angle_slop = 1
[docs]
def __init__(self, config=None, *, logger=None, **kwargs):
super().__init__(config, logger=logger, **kwargs)
shape = self.data_shape
self._z[0] = np.zeros(shape, dtype=float)
if self.bin_type == 'LogMultipole':
self._z[1] = np.zeros(shape, dtype=float)
self.logger.debug('Finished building KKKCorr')
@property
def zeta(self):
if self._z[1].size:
return self._z[0] + 1j * self._z[1]
else:
return self._z[0]
[docs]
def finalize(self, vark1, vark2, vark3):
"""Finalize the calculation of the correlation function.
Parameters:
vark1 (float): The variance of the first scalar field.
vark2 (float): The variance of the second scalar field.
vark3 (float): The variance of the third scalar field.
"""
self._finalize()
self._var_num = vark1 * vark2 * vark3
# I don't really understand why the variance is coming out 2x larger than the normal
# formula for LogSAS. But with just Gaussian noise, I need to multiply the numerator
# by two to get the variance estimates to come out right.
if self.bin_type in ['LogSAS', 'LogMultipole']:
self._var_num *= 2
@property
def varzeta(self):
if self._varzeta is None:
self._calculate_varzeta(1)
return self._varzeta[0]
[docs]
def write(self, file_name, *, file_type=None, precision=None, write_patch_results=False,
write_cov=False):
super().write(file_name, file_type=file_type, precision=precision,
write_patch_results=write_patch_results, write_cov=write_cov)
write.__doc__ = Corr3.write.__doc__.format(
r"""
zeta The estimator of :math:`\zeta` (For LogMultipole, this is split
into real and imaginary parts, zetar and zetai.)
sigma_zeta The sqrt of the variance estimate of :math:`\zeta`
(if rrr is given)
""")
@property
def _write_class_col_names(self):
if self.bin_type == 'LogMultipole':
return ['zetar', 'zetai', 'sigma_zeta']
else:
return ['zeta', 'sigma_zeta']
@property
def _write_class_data(self):
if self.bin_type == 'LogMultipole':
return [self._z[0], self._z[1], np.sqrt(self.varzeta) ]
else:
return [self.zeta, np.sqrt(self.varzeta)]
def _read_from_data(self, data, params):
super()._read_from_data(data, params)
s = self.data_shape
if self.bin_type == 'LogMultipole':
self._z[0] = data['zetar'].reshape(s)
self._z[1] = data['zetai'].reshape(s)
else:
self._z[0] = data['zeta'].reshape(s)
self._varzeta = [data['sigma_zeta'].reshape(s)**2]