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

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 lsst.sims.maf.stackers import snStacker
5import numpy.lib.recfunctions as rf
7__all__ = ['SNSLMetric']
10class SNSLMetric(metrics.BaseMetric):
11 def __init__(self, metricName='SNSLMetric',
12 mjdCol='observationStartMJD', RaCol='fieldRA', DecCol='fieldDec',
13 filterCol='filter', exptimeCol='visitExposureTime',
14 nightCol='night', obsidCol='observationId', nexpCol='numExposures',
15 vistimeCol='visitTime', m5Col='fiveSigmaDepth', season=[-1], night_collapse=False,
16 uniqueBlocks=False, season_gap=80., **kwargs):
17 """
18 Strongly Lensed SN metric
20 The number of is given by:
22 N (lensed SNe Ia with well measured time delay) = 45.7 * survey_area /
23 (20000 deg^2) * cumulative_season_length / (2.5 years) / (2.15 *
24 exp(0.37 * gap_median_all_filter))
26 where:
27 survey_area: survey area (in deg2)
28 cumulative_season_length: cumulative season length (in years)
29 gap_median_all_filter: median gap (all filters)
31 Parameters
32 --------------
33 metricName : str, opt
34 metric name
35 Default : SNCadenceMetric
36 mjdCol : str, opt
37 mjd column name
38 Default : observationStartMJD,
39 RaCol : str,opt
40 Right Ascension column name
41 Default : fieldRa
42 DecCol : str,opt
43 Declinaison column name
44 Default : fieldDec
45 filterCol : str,opt
46 filter column name
47 Default: filter
48 exptimeCol : str,opt
49 exposure time column name
50 Default : visitExposureTime
51 nightCol : str,opt
52 night column name
53 Default : night
54 obsidCol : str,opt
55 observation id column name
56 Default : observationId
57 nexpCol : str,opt
58 number of exposure column name
59 Default : numExposures
60 vistimeCol : str,opt
61 visit time column name
62 Default : visitTime
63 season: int (list) or -1, opt
64 season to process (default: -1: all seasons)
67 """
68 self.mjdCol = mjdCol
69 self.filterCol = filterCol
70 self.RaCol = RaCol
71 self.DecCol = DecCol
72 self.exptimeCol = exptimeCol
73 self.nightCol = nightCol
74 self.obsidCol = obsidCol
75 self.nexpCol = nexpCol
76 self.vistimeCol = vistimeCol
77 self.seasonCol = 'season'
78 self.m5Col = m5Col
79 self.season_gap = season_gap
81 cols = [self.nightCol, self.filterCol, self.mjdCol, self.obsidCol,
82 self.nexpCol, self.vistimeCol, self.exptimeCol]
84 super(SNSLMetric, self).__init__(
85 col=cols, metricName=metricName, units='N SL', **kwargs)
86 self.badVal = 0
87 self.season = season
88 self.bands = 'ugrizy'
90 self.night_collapse = night_collapse
92 def run(self, dataSlice, slicePoint=None):
93 """
94 Runs the metric for each dataSlice
96 Parameters
97 ---------------
98 dataSlice: simulation data
99 slicePoint: slicePoint(default None)
101 Returns
102 -----------
103 number of SL time delay supernovae
105 """
106 dataSlice.sort(order=self.mjdCol)
107 # get the pixel area
108 area = hp.nside2pixarea(slicePoint['nside'], degrees=True)
110 if len(dataSlice) == 0:
111 return self.badVal
113 # Collapse down by night if requested
114 if self.night_collapse:
115 # Or maybe this should be specific per filter?
116 key = np.char.array(dataSlice[self.nightCol].astype(str)) + np.char.array(dataSlice[self.filterCol].astype(str))
117 u_key, indx = np.unique(key, return_index=True)
118 # Normally we would want to co-add depths, increase the number of exposures, average mjdCol. But none of that gets used later.
119 dataSlice = dataSlice[indx]
120 # Need to resort I think
121 dataSlice.sort(order=self.mjdCol)
123 dataSlice, season_id = self.seasonCalc(dataSlice)
125 seasons = self.season
127 if self.season == [-1]:
128 seasons = np.unique(season_id)
130 season_lengths = []
131 median_gaps = []
132 for season in seasons:
133 idx = np.where(season_id == season)[0]
134 slice_sel = dataSlice[idx]
135 if len(slice_sel) < 5:
136 continue
137 mjds_season = dataSlice[self.mjdCol][idx]
138 cadence = mjds_season[1:]-mjds_season[:-1]
139 season_lengths.append(mjds_season[-1]-mjds_season[0])
140 median_gaps.append(np.median(cadence))
142 # get the cumulative season length
144 cumul_season_length = np.sum(season_lengths)
146 if cumul_season_length == 0:
147 return self.badVal
148 # get gaps
149 gap_median = np.mean(median_gaps)
151 # estimate the number of lensed supernovae
152 cumul_season = cumul_season_length/(12.*30.)
154 N_lensed_SNe_Ia = 45.7 * area / 20000. * cumul_season /\
155 2.5 / (2.15 * np.exp(0.37 * gap_median))
157 return N_lensed_SNe_Ia
159 def seasonCalc(self, obs):
160 """
161 Method to estimate seasons
163 Parameters
164 --------------
165 obs: numpy array
166 array of observations
167 season_gap: float, opt
168 minimal gap required to define a season (default: 80 days)
169 mjdCol: str, opt
170 col name for MJD infos (default: observationStartMJD)
172 Returns
173 ----------
174 original numpy array sorted and season
176 """
178 # check wether season has already been estimated
179 if 'season' in obs.dtype.names:
180 return obs, obs['season']
182 obs.sort(order=self.mjdCol)
183 season = np.zeros(obs.size, dtype=int)
185 if len(obs) == 1:
186 return obs, season
188 diff = obs[self.mjdCol][1:]-obs[self.mjdCol][:-1]
189 flag = np.where(diff > self.season_gap)[0]
190 for i, indx in enumerate(flag):
191 season[indx+1:] = i+1
193 return obs, season