Source code for rubin_sim.maf.metrics.agn_time_lag_metric
__all__ = ("AgnTimeLagMetric",)
import numpy as np
from rubin_sim.phot_utils import DustValues
from .base_metric import BaseMetric
[docs]
class AgnTimeLagMetric(BaseMetric):
def __init__(
self,
lag=100,
z=1,
log=False,
threshold=2.2,
calc_type="mean",
mjd_col="observationStartMJD",
filter_col="filter",
m5_col="fiveSigmaDepth",
dust=True,
g_cutoff=22.0,
r_cutoff=21.8,
metric_name=None,
**kwargs,
):
self.lag = lag
self.z = z
self.log = log
self.threshold = threshold
self.calc_type = calc_type
self.mjd_col = mjd_col
self.filter_col = filter_col
self.m5_col = m5_col
if metric_name is None:
metric_name = f"AGN_TimeLag_{lag}_days"
self.dust = dust
self.g_cutoff = g_cutoff
self.r_cutoff = r_cutoff
if dust:
maps = ["DustMap"]
dust_properties = DustValues()
self.ax1 = dust_properties.ax1
else:
maps = []
super().__init__(
col=[self.mjd_col, self.filter_col, self.m5_col],
metric_name=metric_name,
maps=maps,
**kwargs,
)
# Calculate NQUIST value for time-lag and sampling time
# (redshift is included in formula if desired)
def _get_nquist_value(self, caden, lag, z):
return lag / ((1 + z) * caden)
[docs]
def run(self, data_slice, slice_point=None):
# Dust extinction
filterlist = np.unique(data_slice[self.filter_col])
if self.dust:
m5 = np.zeros(len(data_slice))
for filtername in filterlist:
in_filt = np.where(data_slice[self.filter_col] == filtername)[0]
a_x = self.ax1[data_slice[self.filter_col][0]] * slice_point["ebv"]
m5[in_filt] = data_slice[self.m5_col][in_filt] - a_x
else:
m5 = data_slice[self.m5_col]
# Identify times which pass magnitude cuts (chosen by AGN contributors)
mjds = np.zeros(len(data_slice))
for filtername in filterlist:
in_filt = np.where(data_slice[self.filter_col] == filtername)[0]
if filtername in ("u", "i", "z", "y", "r", "g"):
mjds[in_filt] = data_slice[self.mjd_col][in_filt]
elif filtername == "g":
faint = np.where(m5[in_filt] > self.g_cutoff)
mjds[in_filt][faint] = data_slice[self.mjd_col][in_filt][faint]
elif filtername == "r":
faint = np.where(m5[in_filt] > self.r_cutoff)
mjds[in_filt][faint] = data_slice[self.mjd_col][in_filt][faint]
# Remove the visits which were not faint enough
mjds = mjds[np.where(mjds > 0)]
# Calculate differences in time between visits
mv = np.sort(mjds)
val = np.diff(mv)
# If there was only one visit; bail out now.
if len(val) == 0:
return self.badval
# Otherwise summarize the time differences as:
if self.calc_type == "mean":
val = np.mean(val)
elif self.calc_type == "min":
val = np.min(val)
elif self.calc_type == "max":
val = np.max(val)
else:
# find the greatest common divisor
val = np.rint(val).astype(int)
val = np.gcd.reduce(val)
# Will always have a value at this point
nquist = self._get_nquist_value(val, self.lag, self.z)
if self.log:
nquist = np.log(nquist)
# Threshold nquist value is 2.2,
# hence we are aiming to show values higher than threshold (2.2) value
threshold = self.threshold
if self.log:
threshold = np.log(threshold)
if nquist < threshold:
nquist = self.badval
return nquist