Skip to content
Snippets Groups Projects
Commit 688b84fd authored by Naresh Adhikari's avatar Naresh Adhikari Committed by Naresh Adhikari
Browse files

Add O3 replay MDC search functionality to RAVEN; fixes #494

parent 5cfcc97a
No related branches found
No related tags found
1 merge request!1035Add O3 replay MDC search functionality to RAVEN; fixes #494
......@@ -38,6 +38,10 @@ Changelog
to the superevent. The automated pipeline is launched and is blocked before sending
if ``EM_SelectedConfident`` is found to be applied.
- Add O3 replay MDC testing with RAVEN pipeline. This will run on the
emfollow-playground server, creating mock coincidences with a frequency
given by the ``joint_O3_replay_freq`` variable.
2.0.3 "Ugly Merman" (2023-02-16)
--------------------------------
......
......@@ -353,6 +353,11 @@ joint_mdc_freq = 2
MDC superevent to test the RAVEN alert pipeline, i.e for every x
MDC superevents an external MDC event is created."""
joint_O3_replay_freq = 10
"""Determines how often an external replay event will be created near an
superevent to test the RAVEN alert pipeline, i.e for every x
O3 replay superevents an external MDC event is created."""
bilby_default_mode = 'fast_test'
"""Sampling mode of bilby"""
......
......@@ -13,20 +13,31 @@ from . import external_triggers
from . import igwn_alert
def create_grb_event(gpstime, pipeline):
def create_grb_event(gpstime, pipeline, se_search):
""" Create a random GRB event for a certain percentage of MDC or O3-replay
superevents.
Parameters
----------
gpstime : float
Event's gps time
pipeline : str
External trigger pipeline name
se_search : str
Search field for preferred event, 'MDC' or 'AllSky'
"""
new_date = str(Time(gpstime, format='gps', scale='utc').isot) + 'Z'
new_TrigID = str(int(gpstime))
fname = str(Path(__file__).parent /
'../tests/data/{}_grb_gcn.xml'.format(pipeline.lower()))
root = etree.parse(fname)
# Change ivorn to indicate is an MDC event
# Change ivorn to indicate if this is an MDC event or O3 replay event
root.xpath('.')[0].attrib['ivorn'] = \
'ivo://lvk.internal/{0}#MDC-test_event{1}'.format(
pipeline if pipeline != 'Swift' else 'SWIFT', new_date).encode()
'ivo://lvk.internal/{0}#{1}_event{2}'.format(
pipeline if pipeline != 'Swift' else 'SWIFT',
'MDC-test' if se_search == 'MDC' else 'O3-replay',
new_date).encode()
# Change times to chosen time
root.find("./Who/Date").text = str(new_date).encode()
......@@ -56,55 +67,89 @@ def create_grb_event(gpstime, pipeline):
pretty_print=True)
def _offset_time(gpstime):
# Reverse when searching around superevents
th_cbc, tl_cbc = app.conf['raven_coincidence_windows']['GRB_CBC']
return gpstime + random.uniform(-tl_cbc, -th_cbc)
def _offset_time(gpstime, group):
""" This function checks coincident time windows for superevents if they
are of Burst or CBC group.
Parameters
----------
gpstime : float
Event's gps time
group : str
Burst or CBC
"""
if group == 'Burst':
th, tl = app.conf['raven_coincidence_windows']['GRB_Burst']
elif group == 'CBC':
th, tl = app.conf['raven_coincidence_windows']['GRB_CBC']
else:
raise AssertionError(
'Invalid group {}. Use only CBC or Burst.'.format(group))
return gpstime + random.uniform(-tl, -th)
def _is_joint_mdc(graceid):
"""Upload external event to every ten MDCs
def _is_joint_mdc(graceid, se_search):
"""Upload external events to the user-defined frequency of MDC or AllSky
superevents.
Looks at the ending letters of a superevent (e.g. 'ac' from 'MS190124ac'),
converts to a number, and checks if divisible by a number given in the
configuration file.
For example, if the configuration number 'joint_mdc_freq' is 10,
For example, if the configuration number
:obj:`~gwcelery.conf.joint_mdc_freq` is 10,
this means joint events with superevents ending with 'j', 't', 'ad', etc.
"""
end_string = re.split(r'\d+', graceid)[-1].lower()
val = 0
for i in range(len(end_string)):
val += (ord(end_string[i]) - 96) * 26 ** (len(end_string) - i - 1)
return val % int(app.conf['joint_mdc_freq']) == 0
return val % int(app.conf['joint_mdc_freq']) == 0 if se_search == 'MDC' \
else val % int(app.conf['joint_O3_replay_freq']) == 0
@igwn_alert.handler('mdc_superevent',
'superevent',
queue='exttrig',
shared=False)
def upload_external_event(alert):
"""Upload a random GRB event for a certain percentage of MDC superevents.
Every n MDC superevents, upload a Fermi-like GRB candidate within the
standard CBC-GRB search window, where the frequency n is determined by
the configuration variable 'joint_mdc_freq'.
"""Upload a random GRB event for a certain percentage of MDC
or O3-replay superevents.
Notes
-----
Every n superevents, upload a GRB candidate within the
standard CBC-GRB or Burst-GRB search window, where the frequency n is
determined by the configuration variable
:obj:`~gwcelery.conf.joint_mdc_freq` or
:obj:`~gwcelery.conf.joint_O3_replay_freq`.
For O3 replay testing with RAVEN pipeline, only run on gracedb-playground.
"""
# Only create external MDC for the occasional MDC superevent
if not _is_joint_mdc(alert['uid']) or alert['alert_type'] != 'new':
if alert['alert_type'] != 'new':
return
se_search = alert['object']['preferred_event_data']['search']
group = alert['object']['preferred_event_data']['group']
is_gracedb_playground = app.conf['gracedb_host'] \
== 'gracedb-playground.ligo.org'
joint_mdc_alert = se_search == 'MDC' and _is_joint_mdc(alert['uid'], 'MDC')
joint_allsky_alert = se_search == 'AllSky' and \
_is_joint_mdc(alert['uid'], 'AllSky') and is_gracedb_playground
if not (joint_mdc_alert or joint_allsky_alert):
return
# Potentially upload 1, 2, or 3 GRB events
num = 1 + np.random.choice(np.arange(3), p=[.6, .3, .1])
events = []
pipelines = []
for i in range(num):
gpstime = float(alert['object']['t_0'])
new_time = _offset_time(gpstime)
new_time = _offset_time(gpstime, group)
# Choose external grb pipeline to simulate
pipeline = np.random.choice(['Fermi', 'Swift', 'INTEGRAL', 'AGILE'],
p=[.5, .3, .1, .1])
ext_event = create_grb_event(new_time, pipeline)
ext_event = create_grb_event(new_time, pipeline, se_search)
# Upload as from GCN
external_triggers.handle_grb_gcn(ext_event)
......
from unittest.mock import call, patch
import pytest
from unittest.mock import call, Mock
from . import data
from .. import app
from ..tasks import first2years_external
from ..util import read_json
@patch('gwcelery.tasks.external_skymaps.create_upload_external_skymap.run')
@patch('gwcelery.tasks.external_skymaps.get_upload_external_skymap.run')
@patch('gwcelery.tasks.detchar.check_vectors.run')
@patch('gwcelery.tasks.gracedb.create_event.run', return_value={
'graceid': 'E1', 'gpstime': 1, 'instruments': '', 'pipeline': 'Fermi',
'search': 'GRB',
'extra_attributes': {'GRB': {'trigger_duration': 1, 'trigger_id': 123,
'ra': 0., 'dec': 0., 'error_radius': 10.}},
'links': {'self': 'https://gracedb.ligo.org/events/E356793/'}})
@patch('gwcelery.tasks.gracedb.get_events', return_value=[])
def test_handle_create_grb_event(mock_get_events,
mock_create_event,
mock_check_vectors,
mock_get_upload_external_skymap,
mock_create_upload_external_skymap):
@pytest.mark.parametrize(
'host,se_search,group,superevent_id,expected_result',
[['gracedb-playground.ligo.org', 'MDC', 'CBC', 'MS180616j', True],
['gracedb-playground.ligo.org', 'AllSky', 'CBC', 'MS180616j', True],
['gracedb-playground.ligo.org', 'AllSky', 'Burst', 'MS180616j', True],
['gracedb-playground.ligo.org', 'BBH', 'CBC', 'MS180616j', False],
['gracedb-playground.ligo.org', 'AllSky', 'Test', 'TS180616j', False],
['gracedb.ligo.org', 'MDC', 'CBC', 'MS180616j', True],
['gracedb.ligo.org', 'AllSky', 'CBC', 'MS180616j', False],
['gracedb.ligo.org', 'AllSky', 'Burst', 'MS180616j', False],
['gracedb.ligo.org', 'MDC', 'CBC', 'MS180616k', False]])
def test_handle_create_grb_event(monkeypatch,
host,
se_search,
group,
superevent_id,
expected_result):
# Test IGWN alert payload.
alert = read_json(data, 'igwn_alert_superevent_creation.json')
alert['uid'] = 'MS180616j'
alert['uid'] = superevent_id
alert['object']['superevent_id'] = alert['uid']
alert['object']['preferred_event_data']['search'] = 'MDC'
events, pipelines = first2years_external.upload_external_event(alert)
alert['object']['preferred_event_data']['search'] = se_search
alert['object']['preferred_event_data']['group'] = group
mock_create_upload_external_skymap = Mock()
mock_get_upload_external_skymap = Mock()
mock_check_vectors = Mock()
mock_create_event = Mock(
return_value={'graceid': 'E1',
'gpstime': 1,
'instruments': '',
'pipeline': 'Fermi',
'search': 'GRB',
'extra_attributes':
{'GRB': {'trigger_duration': 1,
'trigger_id': 123,
'ra': 0., 'dec': 0.,
'error_radius': 10.}},
'links': {
'self':
'https://gracedb.ligo.org/events/E356793/'}})
mock_get_events = Mock(return_value=[])
monkeypatch.setattr(
'gwcelery.tasks.external_skymaps.create_upload_external_skymap.run',
mock_create_upload_external_skymap)
monkeypatch.setattr(
'gwcelery.tasks.external_skymaps.get_upload_external_skymap.run',
mock_get_upload_external_skymap)
monkeypatch.setattr('gwcelery.tasks.detchar.check_vectors.run',
mock_check_vectors)
monkeypatch.setattr('gwcelery.tasks.gracedb.create_event.run',
mock_create_event)
monkeypatch.setattr('gwcelery.tasks.gracedb.get_events',
mock_get_events)
monkeypatch.setattr(app.conf, 'gracedb_host', host)
if group == 'Test':
with pytest.raises(AssertionError):
first2years_external.upload_external_event(alert)
res = None
else:
res = first2years_external.upload_external_event(alert)
if not expected_result:
assert res is None
events, pipelines = [], []
else:
events, pipelines = res
calls = []
for i in range(len(events)):
calls.append(call(filecontents=events[i],
search='MDC',
search='MDC' if se_search == 'MDC' else 'GRB',
pipeline=pipelines[i],
group='External',
labels=None))
mock_create_event.assert_has_calls(calls)
mock_create_upload_external_skymap.assert_called()
if expected_result:
mock_create_event.assert_has_calls(calls)
mock_create_upload_external_skymap.assert_called()
else:
mock_create_event.assert_not_called()
mock_create_upload_external_skymap.assert_not_called()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment