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
3"""
4Poll GraceDB for new superevents that have been marked EM_READY and have had a
5GCN Notice VOEvent generated. Download and handle those GCN Notices. Runs as a
6script checking for new VOEvents when called from the command line.
7"""
9import os
10from math import ceil
11import logging
12from llama.utils import (
13 DEFAULT_RUN_DIR,
14 LOGDIR,
15 COLOR,
16)
17from llama.event import Event
18from llama.files.lvc_skymap import (
19 SKYMAP_FILENAMES,
20 SkymapNotFoundError,
21)
23GRACEDB_POLL_LOGFILE = os.path.join(LOGDIR, "llama.poll.gracedb.log")
24LOGGER = logging.getLogger(__name__)
25LOGGER.setLevel(logging.DEBUG)
27# number of seconds to look back; set to ~2 days
28LOOKBACK = 2*10**5
31def gpsnow():
32 """
33 Get the current GPS time (rounded up to the nearest integer for
34 GraceDB's querying interface).
35 """
36 import astropy
37 return ceil(astropy.time.Time.now().gps)
40def gracedb_query(gps, lookback=LOOKBACK):
41 """
42 Get a GraceDB-compatible query string for finding recent superevents
43 that happened in the last ``lookback`` seconds before the GPS time ``gps``.
44 """
45 # TODO This doesn't work as advertised on
46 # https://gracedb.ligo.org/documentation/queries.html
47 return "label: EM_READY gpstime: {} .. {}".format(gps, gps-LOOKBACK)
50def superevents():
51 """
52 Get a generator of superevents with skymaps that stops iterating once
53 we've gone through all the events in the last ``LOOKBACK`` seconds.
54 """
55 from llama.com.gracedb import GraceDb
56 earliest_gps = gpsnow() - LOOKBACK
57 for superevent in GraceDb().superevents("SKYMAP_READY"):
58 if superevent['t_start'] < earliest_gps:
59 return superevent
60 yield superevent
63def get_skymap_name(superevent):
64 """Get candidate skymap filenames for this superevent dictionary."""
65 from llama.com.gracedb import GraceDb
66 files = GraceDb().files(superevent['preferred_event']).json()
67 for fname in files:
68 if fname.endswith(".fits") or fname.endswith(".fits.gz"):
69 if fname in SKYMAP_FILENAMES:
70 return fname
71 raise SkymapNotFoundError("Could not find skymap in {}".format(files))
74def fetch_recent(rundir=DEFAULT_RUN_DIR):
75 """Fetch and store recent superevents."""
76 for superevent in superevents():
77 superid = superevent['superevent_id']
78 LOGGER.debug("Checking superevent: %s", superid)
79 LOGGER.info("FAR: %s", superevent['far'])
80 event = Event(superid, rundir=rundir)
81 if event.exists():
82 LOGGER.info("Event directory exists for %s...", superid)
83 if event.files.SkymapInfo.exists():
84 LOGGER.info("SkymapInfo exists for %s, SKIPPING.", superid)
85 continue
86 else:
87 LOGGER.info(COLOR.blue("NEW SUPEREVENT: %s"), superid)
88 LOGGER.debug("Initializing eventdir for %s", superid)
89 event.init()
90 LOGGER.debug("...done. Setting ROLE flag to observation.")
91 event.flags['ROLE'] = 'observation'
92 LOGGER.debug("...done. Making ``SkymapInfo`` for %s", superid)
93 try:
94 event.files.SkymapInfo.generate_from_gracedb_superevent(
95 superid,
96 get_skymap_name(superevent)
97 )
98 except SkymapNotFoundError as err:
99 LOGGER.error("No valid skymap found for %s: %s", superid, err)
100 LOGGER.info(COLOR.green("Done with %s"), superid)
101 # TODO add a VOEvent puller