Examples
Basic K-correction Calculation
The way kcorrect
works is that the user initializes an object of
the Kcorrect class
for the
specific set of response functions for the photometry they are
interested in. This object takes a bit of time to calculate, because
it precalculates the projections of the K-correction templates onto
the response function on a grid of redshifts.
Given redshifts and photometry in units of maggies (and their inverse
variance), the object’s fit_coeffs
method fits the templates to
the photometry.
These coefficients can then be used to calculate the kcorrections with
the kcorrect
method.
Below is an example run on a single object, for which redshift
is
a scalar, and maggies
and ivar
are 1-dimensional arrays. We
can input the arrays as ndarrays or as lists.
import kcorrect.kcorrect
responses = ['sdss_u0', 'sdss_g0', 'sdss_r0', 'sdss_i0', 'sdss_z0']
kc = kcorrect.kcorrect.Kcorrect(responses=responses)
redshift = 0.0826
maggies = [27.26e-9, 73.98e-9, 132.56e-9, 198.52e-9, 238.05e-9]
ivar = [1.528e+18, 5.23e+18, 2.429e+18, 1.042e+18, 0.1653e+18]
# "coeffs" is a [5]-array with coefficients multiplying each template
coeffs = kc.fit_coeffs(redshift=redshift, maggies=maggies, ivar=ivar)
# "k" is a [5]-array with the K-corrections in magnitude units
k = kc.kcorrect(redshift=redshift, coeffs=coeffs)
For multiple objects (and optionally for single objects), redshift
is a 1-dimensional array, whereas maggies
and ivar
are
2-dimensional arrays. Again, these can be input as lists too, as shown
below.
import kcorrect.kcorrect
responses = ['sdss_u0', 'sdss_g0', 'sdss_r0', 'sdss_i0']
kc = kcorrect.kcorrect.Kcorrect(responses=responses)
redshift = [0.0826, 0.111]
maggies = [[27.26e-9, 73.98e-9, 132.56e-9, 198.52e-9],
[4.022e-9, 29.36e-9, 98.230e-9, 155.63e-9]]
ivar = [[1.528e+18, 5.23e+18, 2.429e+18, 1.042e+18],
[2.360e+18, 9.87e+18, 3.006e+18, 1.122e+18]]
# "coeffs" is a [2,5]-array coefficients multiplying each template
coeffs = kc.fit_coeffs(redshift=redshift, maggies=maggies, ivar=ivar)
# "k" is a [2,4]-array with the K-corrections in magnitude units
k = kc.kcorrect(redshift=redshift, coeffs=coeffs)
Absolute magnitudes
The absmag
method
returns absolute magnitudes.
The code returns:
for those bands for which the observed maggies are positive and have a positive inverse variance. For other bands, the returned absolute magnitude is determined using the reconstructed maggies (see next section).
absmag = kc.absmag(redshift=redshift, maggies=maggies, ivar=ivar, coeffs=coeffs)
If one of the maggies is zero or negative, the corresponding absolute magnitude
is returned as -9999
. In the code below, the u-band absolute magnitude
of the first object should have this value.
maggies = [[-3.26e-9, 73.98e-9, 132.56e-9, 198.52e-9],
[4.022e-9, 29.36e-9, 98.230e-9, 155.63e-9]]
coeffs = kc.fit_coeffs(redshift=redshift, maggies=maggies, ivar=ivar)
absmag = kc.absmag(redshift=redshift, maggies=maggies, ivar=ivar, coeffs=coeffs)
In these cases, the method can calculate the one-sigma absolute magnitude limit based
on the inverse variance, if it is not zero, by setting the limit
keyword to True
.
This returns the one-sigma detection limit for all objects and bands (even the detected
ones).
absmag, absmag_limit = kc.absmag(redshift=redshift, maggies=maggies, ivar=ivar, coeffs=coeffs, limit=True)
If one of the input inverse variances is zero or negative, the corresponding
absolute magnitude and (if it is requested) the limit are returned as
-9999
.
ivar = [[0., 0., 2.429e+18, 1.042e+18],
[4.022e-9, 29.36e-9, 98.230e-9, 155.63e-9]]
coeffs = kc.fit_coeffs(redshift=redshift, maggies=maggies, ivar=ivar)
absmag, absmag_limit = kc.absmag(redshift=redshift, maggies=maggies, ivar=ivar, coeffs=coeffs, limit=True)
There is also an option to return the reconstructed absolute magnitude from the full SED fit. This will differ somewhat from the absolute magnitude generated through applying the K-correction, of course, because the SED fit is not a perfect fit to the data. It may be a useful quantity in assessing the goodness of fit (though the reconstructed maggies are a more direct comparison to the input data, see below). It also may be useful as a guess of the absolute magnitude for missing bands.
absmag, absmag_reconstruct = kc.absmag(redshift=redshift, maggies=maggies, ivar=ivar, coeffs=coeffs, reconstruct=True)
Reconstructing spectra and fluxes
The model expressed by the coefficients is a full SED. The
Kcorrect
object has an
attribute templates
that is an instance of the Template
class.
Each template is in units of \({\rm ~erg} {\rm ~s}^{-1} {\rm ~cm}^{-2} {\rm ~A}^{-1} {\rm ~}M_\odot^{-1}\) as observed for a galaxy at 10pc distance. The coefficients are in units of “the solar masses corresponding to a galaxy at 10pc” (see next section).
It is straightforward to use the templates to reconstruct what that SED looks like. If you have found coefficients as in the first example above, the following code will return the SED in \({\rm ~erg} {\rm ~s}^{-1} {\rm ~cm}^{-2} {\rm ~A}^{-1}\). The templates have to be shifted to the observed frame (conserving bolometric flux) to get the correct observed spectrum.
import matplotlib.pyplot as plt
import numpy as np
wave = kc.templates.restframe_wave * (1. + redshift)
spec = coeffs.dot(kc.templates.restframe_flux) / (1. + redshift)
plt.plot(np.log10(wave), np.log10(spec))
plt.xlabel('$\\log_{10} wavelength$')
plt.ylabel('$\\log_{10} flux$ (erg s$^{-1}$ cm$^{-2}$ Ang$^{-1}$')
plt.xlim([3., 4.5])
plt.ylim([-18., -14.])
plt.show()
We can also reconstruct the fluxes from the model (of course we can,
because the K-correction determination must do so!). This is useful to
do to compare the best fit SED to the observations. In the case here
you should find agreement within a few percent between maggies
and
rmaggies
.
rmaggies = kc.reconstruct(redshift=redshift, coeffs=coeffs)
Derived parameters (i.e. stellar mass)
The derived
method
returns some derived parameters. These parameters are described in the
kcorrect paper,
but it is important to take them with a grain of salt.
The only one worth taking at all seriously is mremain
and
mtol
, the surviving stellar mass and mass-to-light ratios in the
stellar population fit. But this parameter is shown to disagree with
other estimates, with a trend of a few tenths of dex across stellar
mass (kcorrect
declining). While I don’t know if any stellar mass
indicator from broad band photometry is great, the one in kcorrect
is particularly simple (and also doesn’t come with any error bar).
Importantly, the mass-to-light ratios are in the output bandpasses
(and you have to specify band_shift
if you want shifted output
bandpasses).
Like the absolute magnitudes, the stellar masses use the cosmo
attribute of the Kcorrect
object, which by default is the Planck18
cosmology from
astropy
.
derived = kc.derived(redshift=redshift, coeffs=coeffs)
# This has one entry per object
stellar_mass = derived['mtol']
# This has one entry per object per output bandpass
mtol = derived['mtol']
Changing the output responses
As one gets to higher redshift, the K-corrections from a given observed frame bandpass to its rest frame counterpart become more and more dependent on the SED model being correct.
One approach to dealing with this is to define a set of output rest
frame bandpasses that are shifted versions of your input bandpasses,
where the shift is the typical redshift of your sample. This minimizes
the internal error in your sample, at the expense of calculating
quantities that are less likely to be comparable to catalogs in the
literature. This option can be utilized by just specifying
band_shift
for the kcorrect
, absmag
, or derived
methods when you use them:
absmag = kc.absmag(redshift=redshift, maggies=maggies, ivar=ivar, coeffs=coeffs, band_shift=0.1)
A second approach is to define a set of output rest frame bandpasses
that correspond closely to the effective rest frame wavelength of the
observed bandpass for galaxies at the typical observed redshift in
your sample. For example, at \(z\sim 0.7\) the observed SDSS
\(r\), \(i\), and \(z\) bands are close in wavelength to
the rest frame \(U\), \(B\), and \(V\) bands. So if we
observed galaxies in the SDSS bands at those redshifts, we could find
the K-corrections to \(UBV\). To do so, we have to instantiate a
Kcorrect
object that can do
so using the response_map
and response_out
arguments:
import kcorrect.kcorrect
responses_in = ['sdss_u0', 'sdss_g0', 'sdss_r0', 'sdss_i0', 'sdss_z0']
responses_out = ['bessell_U', 'bessell_B', 'bessell_V']
responses_map = ['sdss_r0', 'sdss_i0', 'sdss_z0']
kc = kcorrect.kcorrect.Kcorrect(responses=responses_in,
responses_out=responses_out,
responses_map=responses_map)
# These are the ugriz observations (made up!)
redshift = 0.72
maggies = [27.26e-9, 73.98e-9, 132.56e-9, 198.52e-9, 238.05e-9]
ivar = [1.528e+18, 5.23e+18, 2.429e+18, 1.042e+18, 0.1653e+18]
# "coeffs" is a [5]-array with coefficients multiplying each template
coeffs = kc.fit_coeffs(redshift=redshift, maggies=maggies, ivar=ivar)
# "k" is a [3]-array with the K-corrections in magnitude units,
# from riz to UBV.
k = kc.kcorrect(redshift=redshift, coeffs=coeffs)
# "absmag" is also a [3]-array resuling from applying K-corrections
# and the distance modulus
absmag = kc.absmag(redshift=redshift, maggies=maggies, ivar=ivar, coeffs=coeffs)
Monte Carlo Error Estimates
Here we describe how to get K-correction, absolute magnitudes, and
derived quantity errors using a Monte Carlo process built into
kcorrect
.
The error in the K-correction and/or the resoluting absolute magnitude is a problematic quantity. There is no perfect way to calculate it, because even when the statistical errors are small, there are systematic errors to contend with, having to do with the faithfulness and completeness of the template set, the accuracy of the filter curves, and other issues.
For purely statistical errors, in principle if all of the best-fit coefficients are non-zero, we could use the Hessian at the best-fit position to estimate the errors in the coefficients. We could use a matrix of derivatives (i.e. the Jacobian) between the coefficients and the model fluxes to get errors in the model fluxes, and propagate errors to K-corrections and absolute magnitudes. However, this procedure would not work if any of the non-negative coefficients had been pinned to zero, and would also be rather complicated.
Within kcorrect
, we give the user a simple (though expensive) way to
calculate errors through a Monte Carlo process. The
fit_coeffs
method
can generate a Monte Carlo sample using the errors in the input
maggies (assuming Gaussian errors). It will return the Monte Carlo
maggies and their associated best-fit coefficients. Subsequently,
calls to the absmag_mc
and derived_mc
methods will return absolute
magnitudes and derived parameters for the Monte Carlo samples. The
distribution of these quantities then yields the error distribution
around the best-fit value.
The example below shows the use of this technique. It is invoked by
providing fit_coeffs
with a non-zero input
parameter mc
, containing the number of Monte Carlos to
perform. Then after calling absmag_mc
, we can look at the standard
deviation of the absolute magnitudes to get an error estimate. In this
case, the errors are dominated by the statistical error we input, but
try decreasing the u-band inverse variance to get a sense of how the
template fitting uncertainty propagates into the errors.
Note that in calculating the standard deviation, we have to account
for the possibility that the maggies fluctuate negative, in which case
the absolute magnitude is not defined. This is an annoying property of
absolute magnitudes, and to properly deal with this you have to
perform a more careful analysis of the Monte Carlo distribution. In
these circumstances you may also want to look at the absmag_limit
ouput of the absmag
method.
import kcorrect.kcorrect
responses = ['sdss_u0', 'sdss_g0', 'sdss_r0', 'sdss_i0']
kc = kcorrect.kcorrect.Kcorrect(responses=responses)
redshift = [0.0826, 0.111]
maggies = [[27.26e-9, 73.98e-9, 132.56e-9, 198.52e-9],
[4.022e-9, 29.36e-9, 98.230e-9, 155.63e-9]]
ivar = [[1.528e+18, 5.23e+18, 2.429e+18, 1.042e+18],
[2.360e+18, 9.87e+18, 3.006e+18, 1.122e+18]]
# "coeffs" is a [2, 5]-array of coefficients
# "coeffs_mc" is a [2, 5, 100]-array of coefficients for each Monte Carlo
# "maggies_mc" is a [2, 4, 100]-array of the Monte Carloed maggies used
coeffs, coeffs_mc, maggies_mc = kc.fit_coeffs(redshift=redshift, maggies=maggies, ivar=ivar, mc=100)
# "absmag" is a [2, 4]-array of the absolute magnitudes
absmag = kc.absmag(redshift=redshift, maggies=maggies, ivar=ivar, coeffs=coeffs)
# "absmag_mc" is a [2, 4, 100]-array of the Monte Carloed absolute magnitudes
absmag_mc = kc.absmag_mc(redshift=redshift, maggies_mc=maggies_mc, ivar=ivar, coeffs_mc=coeffs_mc)
# The standard deviation over the Monte Carlos is an estimate of errors
absmag_err = absmag_mc.std(axis=2, where=(absmag_mc != -9999.))