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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

"""Create and upload LVC-Fermi sky maps.""" 

import re 

import urllib 

 

from celery import group 

from ligo.skymap.tool import ligo_skymap_combine 

import astropy.utils.data 

import lxml.etree 

 

from . import gracedb 

from ..import app 

from ..util.cmdline import handling_system_exit 

from ..util.tempfile import NamedTemporaryFile 

 

 

def create_combined_skymap(graceid): 

"""Creates and uploads the combined LVC-Fermi skymap. 

 

This also uploads the external trigger skymap to the external trigger 

GraceDB page. 

""" 

preferred_skymap = get_preferred_skymap(graceid) 

message = 'Combined LVC-Fermi sky map using {0}.'.format(preferred_skymap) 

new_skymap = re.findall(r'(.*).fits', preferred_skymap)[0] + '-gbm.fits.gz' 

external_trigger_id = external_trigger(graceid) 

return (external_trigger_heasarc.s(external_trigger_id) | 

get_external_skymap.s() | 

group( 

combine_skymaps.s(gracedb.download(preferred_skymap, 

graceid)) | 

gracedb.upload.s( 

new_skymap, graceid, message, ['sky_loc', 'public']), 

 

gracedb.upload.s('glg_healpix_all_bn_v00.fit', 

external_trigger_id, 

'Sky map from HEASARC.', 

['sky_loc', 'public'])) 

) 

 

 

@app.task(autoretry_for=(ValueError,), retry_backoff=10, 

retry_backoff_max=600) 

def get_preferred_skymap(graceid): 

"""Get the LVC skymap fits filename. 

 

If not available, will try again 10 seconds later, then 20, then 40, etc. 

until up to 10 minutes after initial attempt. 

""" 

gracedb_log = gracedb.get_log(graceid) 

for message in reversed(gracedb_log): 

comment = message['comment'] 

filename = message['filename'] 

if (filename.endswith('.fits.gz') or filename.endswith('.fits')) and \ 

'copied' in comment: 

return filename 

raise ValueError('No skymap available for {0} yet.'.format(graceid)) 

 

 

@app.task(autoretry_for=(ValueError,), retry_backoff=10, 

retry_backoff_max=600) 

def get_external_skymap_filename(graceid): 

"""Get the external skymap fits filename. 

 

If not available, will try again 10 seconds later, then 20, then 40, etc. 

until up to 10 minutes after initial attempt. 

""" 

gracedb_log = gracedb.get_log(graceid) 

for message in reversed(gracedb_log): 

filename = message['filename'] 

if (filename.endswith('.fits') or filename.endswith('.fit')): 

if 'bayestar' not in filename and 'LALinference' not in filename: 

return filename 

raise ValueError('No external skymap available for {0} yet.'.format( 

graceid)) 

 

 

@app.task(shared=False) 

def combine_skymaps(skymap1filebytes, skymap2filebytes): 

"""This task combines the two input skymaps, in this case the external 

trigger skymap and the LVC skymap and writes to a temporary output file. It 

then returns the contents of the file as a byte array. 

""" 

with NamedTemporaryFile(mode='rb', suffix='.fits.gz') as combinedskymap, \ 

NamedTemporaryFile(content=skymap1filebytes) as skymap1file, \ 

NamedTemporaryFile(content=skymap2filebytes) as skymap2file, \ 

handling_system_exit(): 

ligo_skymap_combine.main([skymap1file.name, 

skymap2file.name, combinedskymap.name]) 

return combinedskymap.read() 

 

 

@app.task(shared=False) 

def external_trigger(graceid): 

"""Returns the associated external trigger GraceDB ID.""" 

em_events = gracedb.get_superevent(graceid)['em_events'] 

if len(em_events): 

for exttrig in em_events: 

if gracedb.get_event(exttrig)['search'] == 'GRB': 

return exttrig 

raise ValueError('No associated GRB EM event(s) for {0}.'.format(graceid)) 

 

 

@app.task(shared=False) 

def external_trigger_heasarc(external_id): 

"""Returns the HEASARC fits file link.""" 

gracedb_log = gracedb.get_log(external_id) 

for message in gracedb_log: 

if 'Original Data' in message['comment']: 

filename = message['filename'] 

xmlfile = gracedb.download(urllib.parse.quote(filename), 

external_id) 

root = lxml.etree.fromstring(xmlfile) 

heasarc_url = root.find('./What/Param[@name="LightCurve_URL"]' 

).attrib['value'] 

return re.sub(r'quicklook(.*)', 'current/', heasarc_url) 

raise ValueError('Not able to retrieve HEASARC link for {0}.'.format( 

external_id)) 

 

 

@app.task(autoretry_for=(urllib.error.HTTPError,), retry_backoff=10, 

retry_backoff_max=600) 

def get_external_skymap(heasarc_link): 

"""Download the Fermi sky map fits file and return the contents as a byte 

array. 

 

If not available, will try again 10 seconds later, then 20, then 40, etc. 

until up to 10 minutes after initial attempt. 

""" 

trigger_id = re.sub(r'.*\/(\D+?)(\d+)(\D+)\/.*', r'\2', heasarc_link) 

skymap_name = 'glg_healpix_all_bn{0}_v00.fit'.format(trigger_id) 

skymap_link = heasarc_link + skymap_name 

return astropy.utils.data.get_file_contents( 

(skymap_link), encoding='binary', cache=False) 

 

 

@app.task(autoretry_for=(urllib.error.HTTPError,), retry_backoff=10, 

retry_backoff_max=60) 

def get_upload_external_skymap(graceid): 

"""If a Fermi sky map is not uploaded yet, tries to download one and upload 

to external event. If sky map is not available, passes so that this can be 

re-run the next time an update GCN notice is received. 

""" 

try: 

filename = get_external_skymap_filename(graceid) 

if 'glg_healpix_all_bn_v00.fit' in filename: 

return 

except ValueError: 

pass 

 

try: 

( 

external_trigger_heasarc.si(graceid) 

| 

get_external_skymap.s().set(max_retries=5) 

| 

gracedb.upload.s( 

'glg_healpix_all_bn_v00.fit', 

graceid, 

'Sky map from HEASARC.', 

['sky_loc']) 

).delay() 

 

except ValueError: 

# Pass if heasarc_link not able to be retrieved. If the sky map is not 

# available a 404 error will still be raised. 

# FIXME: Add automatic generation of external skymap as ini !595 

pass