Hide keyboard shortcuts

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

1# (c) Stefan Countryman, 2019 

2 

3""" 

4A registry of detectors providing uniform naming conventions. 

5 

6Available Detectors 

7------------------- 

8 

9""" 

10 

11from collections import namedtuple 

12from llama.classes import ImmutableDict 

13 

14 

15DetectorTuple = namedtuple( 

16 "DetectorTuple", 

17 ( 

18 "name", 

19 "abbrev", 

20 "fullname", 

21 "url", 

22 "summary", 

23 "description", 

24 "citations", 

25 ) 

26) 

27 

28 

29class TableRowRepresentable(DetectorTuple): 

30 """ 

31 A class for printing ``DetectorTuple`` rows in docstring format for a 

32 table. *This superclass of* ``Detector`` *implements table printing for 

33 ``DetectorTuple`` instances in such a way that it can be reused to generate 

34 the header rows of the ``llama.detectors`` module docstring.* 

35 """ 

36 

37 TABLE_COLUMN_WIDTHS = DetectorTuple(name=13, abbrev=13, fullname=65, 

38 url=None, summary=None, 

39 description=None, citations=None) 

40 

41 def doctable_row(self): 

42 """Get a row describing this ``DetectorTuple`` for inclusion in a table 

43 of all detectors. *This method is defined in a separate class from* 

44 ``Detector`` *because it is also used (in a hacky way) to generate the 

45 table header.*""" 

46 row = "|" 

47 sep = "+" 

48 for field in self.TABLE_COLUMN_WIDTHS._fields: 

49 if getattr(self.TABLE_COLUMN_WIDTHS, field) is not None: 

50 length = getattr(self.TABLE_COLUMN_WIDTHS, field) 

51 string = getattr(self, field) 

52 string = '``None``' if string is None else string 

53 row += (f" {string[:length-3]: <{length-3}}" 

54 f"{'...' if len(string) > length else ' '} |") 

55 sep += '-'*(2+length)+'+' 

56 return f"{row}\n{sep}\n" 

57 

58 

59def doc_table_header(): 

60 """Get the header rows for the table of ``Detector`` instances in 

61 ``llama.detectors.__doc__``.""" 

62 gen = TableRowRepresentable(**{f: f"``{f}``" 

63 for f in DetectorTuple._fields}) 

64 head, sep, end = gen.doctable_row().split('\n') 

65 return '\n'.join((sep, head, sep.replace('-', '='), end)) 

66 

67 

68class Detector(TableRowRepresentable): 

69 """ 

70 An object describing some sort of detector (or, more generally, 

71 a source of data). Use these instances to provide uniform naming 

72 conventions, data source descriptions, and other information across the 

73 pipeline. You shouldn't create ``Detector`` instances outside of the main 

74 detectors file since they are meant to be stored in the same namespace for 

75 shared use throughout the pipeline. On instantiation, an assertion runs to 

76 ensure that there are no name collisions or inconsistencies and to register 

77 the new detector name in the ``detectors`` namespace. This allows 

78 the ``detectors`` submodule to provide a convenient, unified interface for 

79 accessing all defined ``Detector`` isntances and avoid runtime 

80 complications. This name disambiguation is important to keep 

81 automatically-generated code and documentation uniform and unambiguous with 

82 respect to detector 

83 references. 

84 

85 Parameters 

86 ---------- 

87 name : str 

88 The name of the detector. Must be a valid name for a ``python`` 

89 variable, and should correspond to the name of the ``Detector`` in the 

90 ``detectors`` submodule. 

91 abbrev : str 

92 A **very** short abbreviation (think 3 characters) for this detector. 

93 Must be a valid name for a ``python`` variable. This will be used for 

94 dynamically-generated subclasses and filenames. 

95 fullname : str, optional 

96 The full name of the detector (useful for longer detector names). If 

97 ``name`` is an acronym or other abbreviation, then ``fullname`` should 

98 spell out what ``name`` stands for. If not provided, this will take the 

99 same value as ``name``. 

100 url : str, optional 

101 A URL pointing to this detector's homepage (or whatever page best 

102 summarizes this detector/links to other good information about the 

103 detector/offers data access). (default: ``None``) 

104 summary : str, optional 

105 A short (think: one or two lines) sentence that describes the detector. 

106 If not provided, this will take the same value as ``name``. 

107 description : str, optional 

108 An extended (think: up to a few paragraphs) description of the 

109 detector from which a new developer could gain cursory understanding of 

110 the data source. 

111 citations : ImmutableDict, optional 

112 A dictionary of citations which a developer or user can use to learn 

113 more about the detector. Map article titles/names (``str``) to URLs 

114 (``str``) at which those articles can be found, e.g. NASA ADS or arXiv 

115 links. 

116 

117 Raises 

118 ------ 

119 TypeError 

120 If this detector clashes in ``name`` or ``abbrev`` with another 

121 existing detector. 

122 """ 

123 

124 def __new__(cls, name, abbrev, fullname=None, url=None, summary=None, 

125 description="", citations=ImmutableDict({})): 

126 """Initialize a new ``Detector``, providing default values for any 

127 unspecified optional parameters.""" 

128 if not all(isinstance(v, str) for v in citations.values()): 

129 raise TypeError(("Citation URLs must all be ``str`` type. Got: " 

130 "{}").format(citations)) 

131 if not all(isinstance(k, str) for k in citations.keys()): 

132 raise TypeError(("Citation names must all be ``str`` type. Got: " 

133 "{}").format(citations)) 

134 new = DetectorTuple.__new__( 

135 cls, 

136 name=name, 

137 abbrev=abbrev, 

138 fullname=fullname if fullname is not None else name, 

139 url=url, 

140 summary=summary if summary is not None else name, 

141 description=description, 

142 citations=citations, 

143 ) 

144 if not all(isinstance(a, str) for a in (new.name, new.abbrev, 

145 new.fullname, new.summary, 

146 new.description)): 

147 raise TypeError(("``name``, ``abbrev``, ``fullname``, and " 

148 "``summary`` must all be ``str`` type if " 

149 "specified. Got: {}").format(new)) 

150 if not (isinstance(new.url, str) or new.url is None): 

151 raise TypeError(("``url`` must be ``str`` type if specified. Got: " 

152 "{}").format(new)) 

153 cls._register_new_detector(new) 

154 return new 

155 

156 def _register_new_detector(self): 

157 """Register a newly-created detector to the defining module's scope and 

158 check for conflicts with other existing detectors. Raises a 

159 ``TypeError`` if they conflict.""" 

160 det = [d for d in globals().values() 

161 if isinstance(d, Detector)] + [self] 

162 if not len({v for d in det for v in [d.name, d.abbrev]}) == 2*len(det): 

163 raise TypeError(("Found conflicting existing detectors in the " 

164 "``detectors`` module namespace: {}").format(det)) 

165 globals()[self.name] = self 

166 

167 

168IceCube = Detector('IceCube', 'i3', url='http://wiki.icecube.wisc.edu') 

169LVC = Detector('LVC', 'lvc', url='http://wiki.ligo.org') 

170Fermi = Detector('Fermi', 'frm') 

171ZTF = Detector( 

172 'ZTF', 

173 'ztf', 

174 fullname='Zwicky Transient Facility', 

175 url='https://www.ptf.caltech.edu/page/ztf_technical', 

176 citations=ImmutableDict({ 

177 'The Zwicky Transient Facility (Bellm 2014)': 

178 'http://adsabs.harvard.edu/abs/2014arXiv1410.8185B', 

179 'The Zwicky transient facility observing system (Smith et al. 2014)': 

180 'http://adsabs.harvard.edu/abs/2014SPIE.9147E..79S', 

181 'The Zwicky Transient Facility Camera (Dekany et al. 2016)': 

182 'http://adsabs.harvard.edu/abs/2016SPIE.9908E..5MD', 

183 'The unblinking eye on the sky (Bellm and Kulkarni 2017)': 

184 'http://adsabs.harvard.edu/abs/2017NatAs...1E..71B', 

185 }), 

186) 

187LLAMA = Detector( 

188 'LLAMA', 

189 'lma', 

190 url='http://multimessenger.science', 

191 fullname='Low-Latency Algorithm for Multimessenger Astrophysics', 

192 citations=ImmutableDict({ 

193 ( 

194 'Low-Latency Algorithm for Multi-messenger Astrophysics (LLAMA) ' 

195 'with Gravitational-Wave and High-Energy Neutrino Candidates' 

196 ): 'https://arxiv.org/abs/1901.05486', 

197 ( 

198 'Bayesian Multi-Messenger Search Method for Common Sources of ' 

199 'Gravitational Waves and High-Energy Neutrinos' 

200 ): 'https://arxiv.org/abs/1810.11467', 

201 }), 

202) 

203 

204 

205# add the detector parameters to a .rst table in the docstring 

206__doc__ += doc_table_header() 

207for detector in [d for d in locals().values() if isinstance(d, Detector)]: 

208 __doc__ += detector.doctable_row()