Computing hyperbolic magnitudes¶

Implementation of Lupton et al. (1999) by Jan Luca van den Busch.

Hyperbolic magnitudes aim to overcome limitations of classical magnitudes, which are logarithmic in flux. Hyperbolic magnitudues are implemented using the inverse hyperbolic sine and therefore have a linear behaviour in flux at low signal to noise, which gradually transitions to the classical logarithmic scaling at high signal to noise (i.e. equivalent to classical magnitudes in this limit).

This notebooks provides an example of how to convert classical to hyperbolical magnitudes using the pipeline stages HyperbolicSmoothing and HyperbolicMagnitudes in the rail.core module.

In [1]:
import os

import numpy as np
import matplotlib.pyplot as plt

import rail
from rail.core.data import TableHandle
from rail.core.stage import RailStage
from rail.core.utilPhotometry import HyperbolicSmoothing, HyperbolicMagnitudes

We first set up a data store for interactive usage of RAIL (see the rail/examples/goldenspike/goldenspike.ipynb for further examples).

In [2]:
DS = RailStage.data_store
DS.__class__.allow_overwrite = True

Next we load some DC2 sample data that provides LSST ugrizy magnitudes and magnitude errors, which we want to convert to hyperbolic magnitudes.

In [3]:
from rail.core.utils import RAILDIR
testFile = os.path.join(RAILDIR, 'rail', 'examples', 'testdata', 'test_dc2_training_9816.pq')
test_mags = DS.read_file("test_data", TableHandle, testFile)

Determining the smoothing parameters¶

First we run the rail.core.HyperbolicSmoothing stage. This stage computes the smoothing parameter (called $b$ in Lupton et al. 1999), which determines the transition between the linear and logarithmic behaviour of the hyperbolic magnitudes.

The input for this stage is a table containing magnitudes and magnitude errors per object (fluxes are also supported as input data by setting is_flux=True in the configuration). In this example, we assume that the magnitude zeropoint is 0.0 and that we want to convert all 6 LSST bands. This can be specified with the value_columns and error_columns parameters, which list the names of the magnitude columns and their corresponding magnitude errors.

In [4]:
lsst_bands = 'ugrizy'
configuration = dict(
    value_columns=[f"mag_{band}_lsst" for band in lsst_bands],
    error_columns=[f"mag_err_{band}_lsst" for band in lsst_bands],
    zeropoints=[0.0] * len(lsst_bands),
    is_flux=False)

smooth = HyperbolicSmoothing.make_stage(name='hyperbolic_smoothing', **configuration)
smooth.compute(test_mags)
Inserting handle into data store.  parameters_hyperbolic_smoothing: inprogress_parameters_hyperbolic_smoothing.pq, hyperbolic_smoothing
Out[4]:
<rail.core.data.PqHandle at 0x7f2248ef3970>

The output of this stage is a table of relevant statistics required to compute the hyperbolic magnitudes per filter:

  • the median flux error
  • the zeropoint (which can be computed by comparing fluxes and magnitudes in the original hyperbolic code)
  • the reference flux $f_{\rm ref}$ that corresponds to the given zeropoint
  • the smoothing parameter $b$ (in terms of the absolute and the relative flux $x = f / f_{\rm ref}$

The field ID column is currently not used by the RAIL module and can be ignored.

In [5]:
smooth_params = smooth.get_handle("parameters").data
smooth_params
Out[5]:
flux error zeropoint ref. flux b relative b absolute
filter field ID
mag_u_lsst 0 1.559839e-11 0.0 1.0 1.625332e-11 1.625332e-11
mag_g_lsst 0 3.286980e-12 0.0 1.0 3.424989e-12 3.424989e-12
mag_r_lsst 0 3.052049e-12 0.0 1.0 3.180194e-12 3.180194e-12
mag_i_lsst 0 4.441195e-12 0.0 1.0 4.627666e-12 4.627666e-12
mag_z_lsst 0 7.823318e-12 0.0 1.0 8.151793e-12 8.151793e-12
mag_y_lsst 0 1.785106e-11 0.0 1.0 1.860057e-11 1.860057e-11

Computing the magnitudes¶

Based on the smoothing parameters, the hyperbolic magnitudes are computed with be computed by rail.core.HyperbolicMagnitudes.

The input for this module is, again, the table with magnitudes and magnitude errors and the output table of rail.core.HyperbolicSmoothing.

In [6]:
hypmag = HyperbolicMagnitudes.make_stage(name='hyperbolic_magnitudes', **configuration)
hypmag.compute(test_mags, smooth_params)
Inserting handle into data store.  parameters: None, hyperbolic_magnitudes
Inserting handle into data store.  output_hyperbolic_magnitudes: inprogress_output_hyperbolic_magnitudes.pq, hyperbolic_magnitudes
Out[6]:
<rail.core.data.PqHandle at 0x7f2290e9ce20>

The output of this module is a table with hyperbolic magnitudes and their corresponding error.

Note: The current default is to relabel the columns names by substituting mag_ by mag_hyp_. If this substitution is not possible, the column names are identical to the input table with classical magnitudes.

In [7]:
test_hypmags = hypmag.get_handle("output").data
test_hypmags
Out[7]:
mag_hyp_u_lsst mag_hyp_err_u_lsst mag_hyp_g_lsst mag_hyp_err_g_lsst mag_hyp_r_lsst mag_hyp_err_r_lsst mag_hyp_i_lsst mag_hyp_err_i_lsst mag_hyp_z_lsst mag_hyp_err_z_lsst mag_hyp_y_lsst mag_hyp_err_y_lsst
0 18.040370 0.005046 16.960892 0.005001 16.653413 0.005001 16.506310 0.005001 16.466378 0.005001 16.423906 0.005003
1 21.615533 0.009551 20.709402 0.005084 20.533851 0.005048 20.437566 0.005075 20.408885 0.005193 20.388203 0.005804
2 21.851866 0.011146 20.437067 0.005057 19.709715 0.005015 19.312630 0.005016 18.953412 0.005023 18.770441 0.005063
3 19.976499 0.005477 19.128676 0.005011 18.803485 0.005005 18.619996 0.005007 18.546590 0.005014 18.479452 0.005041
4 22.294717 0.015481 21.242782 0.005182 20.911803 0.005084 20.731707 0.005118 20.700288 0.005308 20.644994 0.006211
... ... ... ... ... ... ... ... ... ... ... ... ...
10220 25.732646 0.301680 25.301790 0.047027 25.099622 0.036055 25.180361 0.055825 25.295404 0.108750 25.229366 0.226270
10221 25.251545 0.205102 24.512358 0.023323 24.345662 0.018623 24.434138 0.028559 24.547622 0.055349 24.678486 0.140864
10222 25.147493 0.187751 24.113802 0.016640 23.828346 0.012276 23.711119 0.015380 23.755514 0.027202 23.830545 0.065739
10223 26.305978 0.435503 25.067304 0.038089 24.770026 0.026890 24.586800 0.032711 24.781555 0.068406 24.653411 0.137773
10224 26.429216 0.461142 25.548904 0.058784 24.983338 0.032494 24.889564 0.042924 24.836702 0.071907 24.752944 0.150422

10225 rows × 12 columns

This plot shows the difference between the classical and hyperbolic magnitude as function of the classical $r$-band magnitude. The turn-off point is determined by the value for $b$ estimated above.

In [8]:
filt = "r"

mag_class = test_mags.data[f"mag_{filt}_lsst"]
magerr_class = test_mags.data[f"mag_err_{filt}_lsst"]
mag_hyp = test_hypmags[f"mag_hyp_{filt}_lsst"]
magerr_hyp = test_hypmags[f"mag_hyp_err_{filt}_lsst"]

fig = plt.figure(dpi=100)
plt.axhline(y=0.0, color="k", lw=0.55)
plt.scatter(mag_class, mag_class - mag_hyp, s=1)
plt.xlabel("Classical magnitudue")
plt.ylabel("Classical $-$ hyperbolic magnitude")
plt.title("$r$-band magnitude")
Out[8]:
Text(0.5, 1.0, '$r$-band magnitude')
In [ ]: