Coverage for python/lsst/sims/maf/metrics/snSLMetric.py : 12%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import numpy as np
2import lsst.sims.maf.metrics as metrics
3import healpy as hp
4from .seasonMetrics import calcSeason
5from lsst.sims.photUtils import Dust_values
6from lsst.sims.maf.utils import collapse_night
8__all__ = ['SNSLMetric']
11class SNSLMetric(metrics.BaseMetric):
12 def __init__(self, metricName='SNSLMetric',
13 mjdCol='observationStartMJD', RaCol='fieldRA', DecCol='fieldDec',
14 filterCol='filter', exptimeCol='visitExposureTime',
15 nightCol='night', obsidCol='observationId', nexpCol='numExposures',
16 vistimeCol='visitTime', m5Col='fiveSigmaDepth', season=[-1], night_collapse=False,
17 nfilters_min=4, min_season_obs=5,
18 m5mins={'u': 22.7, 'g': 24.1, 'r': 23.7, 'i': 23.1, 'z': 22.2, 'y': 21.4},
19 maps=['DustMap'], **kwargs):
20 """
21 Strongly Lensed SN metric
23 The number of is given by:
25 N (lensed SNe Ia with well measured time delay) = 45.7 * survey_area /
26 (20000 deg^2) * cumulative_season_length / (2.5 years) / (2.15 *
27 exp(0.37 * gap_median_all_filter))
29 where:
30 survey_area: survey area (in deg2)
31 cumulative_season_length: cumulative season length (in years)
32 gap_median_all_filter: median gap (all filters)
34 Parameters
35 --------------
36 metricName : str, opt
37 metric name
38 Default : SNCadenceMetric
39 mjdCol : str, opt
40 mjd column name
41 Default : observationStartMJD,
42 RaCol : str,opt
43 Right Ascension column name
44 Default : fieldRa
45 DecCol : str,opt
46 Declinaison column name
47 Default : fieldDec
48 filterCol : str,opt
49 filter column name
50 Default: filter
51 exptimeCol : str,opt
52 exposure time column name
53 Default : visitExposureTime
54 nightCol : str,opt
55 night column name
56 Default : night
57 obsidCol : str,opt
58 observation id column name
59 Default : observationId
60 nexpCol : str,opt
61 number of exposure column name
62 Default : numExposures
63 vistimeCol : str,opt
64 visit time column name
65 Default : visitTime
66 season: int (list) or -1, opt
67 season to process (default: -1: all seasons)
68 nfilters_min : int (5)
69 The number of filters to demand in a season
72 """
73 self.mjdCol = mjdCol
74 self.filterCol = filterCol
75 self.RaCol = RaCol
76 self.DecCol = DecCol
77 self.exptimeCol = exptimeCol
78 self.nightCol = nightCol
79 self.obsidCol = obsidCol
80 self.nexpCol = nexpCol
81 self.vistimeCol = vistimeCol
82 self.seasonCol = 'season'
83 self.m5Col = m5Col
84 self.maps= maps
86 cols = [self.nightCol, self.filterCol, self.mjdCol, self.obsidCol,
87 self.nexpCol, self.vistimeCol, self.exptimeCol, self.m5Col]
89 super(SNSLMetric, self).__init__(
90 col=cols, metricName=metricName, maps=self.maps, units='N SL', **kwargs)
91 self.badVal = 0
92 self.season = season
93 self.bands = 'ugrizy'
95 self.night_collapse = night_collapse
96 self.m5mins = m5mins
97 self.min_season_obs = min_season_obs
98 self.nfilters_min = nfilters_min
99 self.phot_properties = Dust_values()
101 def run(self, dataSlice, slicePoint=None):
102 """
103 Runs the metric for each dataSlice
105 Parameters
106 ---------------
107 dataSlice: simulation data
108 slicePoint: slicePoint(default None)
110 Returns
111 -----------
112 number of SL time delay supernovae
114 """
115 dataSlice.sort(order=self.mjdCol)
117 # Crop it down so things are coadded per night at the median MJD time
118 dataSlice = collapse_night(dataSlice, nightCol=self.nightCol, filterCol=self.filterCol,
119 m5Col=self.m5Col, mjdCol=self.mjdCol)
121 # get the pixel area
122 area = hp.nside2pixarea(slicePoint['nside'], degrees=True)
124 if len(dataSlice) == 0:
125 return self.badVal
127 season_id = np.floor(calcSeason(np.degrees(slicePoint['ra']), dataSlice[self.mjdCol]))
129 seasons = self.season
131 if self.season == [-1]:
132 seasons = np.unique(season_id)
134 season_lengths = []
135 median_gaps = []
136 for season in seasons:
137 idx = np.where(season_id == season)[0]
138 bright_enough = np.zeros(idx.size, dtype=bool)
139 for key in self.m5mins:
140 in_filt = np.where(dataSlice[idx][self.filterCol] == key)[0]
141 A_x = self.phot_properties.Ax1[key] * slicePoint['ebv']
142 bright_enough[in_filt[np.where((dataSlice[idx[in_filt]][self.m5Col] - A_x) > self.m5mins[key])[0]]] = True
143 idx = idx[bright_enough]
144 u_filters = np.unique(dataSlice[idx][self.filterCol])
145 if (len(idx) < self.min_season_obs) | (np.size(u_filters) < self.nfilters_min):
146 continue
147 if self.night_collapse:
148 u_nights, unight_indx = np.unique(dataSlice[idx][self.nightCol], return_index=True)
149 idx = idx[unight_indx]
150 order = np.argsort(dataSlice[self.mjdCol][idx])
151 idx = idx[order]
152 mjds_season = dataSlice[self.mjdCol][idx]
153 cadence = mjds_season[1:]-mjds_season[:-1]
154 season_lengths.append(mjds_season[-1]-mjds_season[0])
155 median_gaps.append(np.median(cadence))
157 # get the cumulative season length
159 cumul_season_length = np.sum(season_lengths)
161 if cumul_season_length == 0:
162 return self.badVal
163 # get gaps
164 gap_median = np.mean(median_gaps)
166 # estimate the number of lensed supernovae
167 cumul_season = cumul_season_length/(12.*30.)
169 N_lensed_SNe_Ia = 45.7 * area / 20000. * cumul_season /\
170 2.5 / (2.15 * np.exp(0.37 * gap_median))
172 return N_lensed_SNe_Ia