From 64285bfa62cb6e161b844051566fc2f24396b8d2 Mon Sep 17 00:00:00 2001
From: Brandon Piotrzkowski <brandon.piotrzkowski@ligo.org>
Date: Tue, 20 Sep 2022 15:55:55 -0400
Subject: [PATCH] Get trigger ID for INTEGRAL notices from IVORN; fixes #437

---
 CHANGES.rst                                   |  3 ++
 gwcelery/tasks/external_triggers.py           | 32 +++++++++++++------
 gwcelery/tests/data/integral_grb_gcn.xml      |  2 +-
 .../tests/test_tasks_external_triggers.py     | 27 ++++++++++------
 4 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index 99f5bd330..f68dfb69d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -42,6 +42,9 @@ Changelog
     emfollow-playground server, creating mock coincidences with a frequency
     given by the ``joint_O3_replay_freq`` variable.
 
+-   Fix collation of INTEGRAL notices by getting the GCN ID from the IVORN
+    field.
+
 2.0.3 "Ugly Merman" (2023-02-16)
 --------------------------------
 
diff --git a/gwcelery/tasks/external_triggers.py b/gwcelery/tasks/external_triggers.py
index 0aa3d4a5e..6a0b5711b 100644
--- a/gwcelery/tasks/external_triggers.py
+++ b/gwcelery/tasks/external_triggers.py
@@ -101,22 +101,34 @@ def handle_grb_gcn(payload):
     u = urlparse(root.attrib['ivorn'])
     stream_path = u.path
 
-    #  Get TrigID
-    try:
-        trig_id = root.find("./What/Param[@name='TrigID']").attrib['value']
-    except AttributeError:
-        trig_id = root.find("./What/Param[@name='Trans_Num']").attrib['value']
-    ext_group = 'Test' if root.attrib['role'] == 'test' else 'External'
-
-    notice_type = \
-        int(root.find("./What/Param[@name='Packet_Type']").attrib['value'])
-
     stream_obsv_dict = {'/SWIFT': 'Swift',
                         '/Fermi': 'Fermi',
                         '/INTEGRAL': 'INTEGRAL',
                         '/AGILE': 'AGILE'}
     event_observatory = stream_obsv_dict[stream_path]
 
+    #  Get TrigID
+    if event_observatory == 'INTEGRAL':
+        #  FIXME: revert all this if INTEGRAL fixes their GCN notices
+        #  If INTGRAL, get trigger ID from ivorn rather than the TrigID field
+        trig_id = u.fragment.split('_')[-1].split('-')[0]
+        #  Modify the TrigID field so GraceDB has the correct value
+        root.find("./What/Param[@name='TrigID']").attrib['value'] = \
+            str(trig_id).encode()
+        #  Apply changes to payload delivered to GraceDB
+        payload = etree.tostring(root, xml_declaration=True, encoding="UTF-8")
+    else:
+        try:
+            trig_id = \
+                root.find("./What/Param[@name='TrigID']").attrib['value']
+        except AttributeError:
+            trig_id = \
+                root.find("./What/Param[@name='Trans_Num']").attrib['value']
+    ext_group = 'Test' if root.attrib['role'] == 'test' else 'External'
+
+    notice_type = \
+        int(root.find("./What/Param[@name='Packet_Type']").attrib['value'])
+
     reliability = root.find("./What/Param[@name='Reliability']")
     if reliability is not None and int(reliability.attrib['value']) <= 4:
         return
diff --git a/gwcelery/tests/data/integral_grb_gcn.xml b/gwcelery/tests/data/integral_grb_gcn.xml
index 225dd325d..6dfcea7b6 100644
--- a/gwcelery/tests/data/integral_grb_gcn.xml
+++ b/gwcelery/tests/data/integral_grb_gcn.xml
@@ -1,6 +1,6 @@
 <?xml version = '1.0' encoding = 'UTF-8'?>
 <voe:VOEvent
-      ivorn="ivo://nasa.gsfc.gcn/INTEGRAL#Wakeup_Pos_000000-0-640"
+      ivorn="ivo://nasa.gsfc.gcn/INTEGRAL#Wakeup_Pos_123456-0-640"
       role="observation" version="2.0"
       xmlns:voe="http://www.ivoa.net/xml/VOEvent/v2.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
diff --git a/gwcelery/tests/test_tasks_external_triggers.py b/gwcelery/tests/test_tasks_external_triggers.py
index a4cd9612b..b670d9f2b 100644
--- a/gwcelery/tests/test_tasks_external_triggers.py
+++ b/gwcelery/tests/test_tasks_external_triggers.py
@@ -1,4 +1,5 @@
-from importlib.resources import read_binary
+from importlib import resources
+from lxml import etree
 from unittest.mock import patch, call
 
 import pytest
@@ -28,7 +29,15 @@ def test_handle_create_grb_event(mock_create_event,
                                  mock_get_upload_external_skymap,
                                  mock_create_upload_external_skymap,
                                  pipeline, path):
-    text = read_binary(data, path)
+    if pipeline == 'INTEGRAL':
+        with resources.path(data, path) as p:
+            fname = str(p)
+        root = etree.parse(fname)
+        root.find("./What/Param[@name='TrigID']").attrib['value'] = \
+            '123456'.encode()
+        text = etree.tostring(root, xml_declaration=True, encoding="UTF-8")
+    else:
+        text = resources.read_binary(data, path)
     external_triggers.handle_grb_gcn(payload=text)
     mock_create_event.assert_called_once_with(filecontents=text,
                                               search='GRB',
@@ -95,10 +104,10 @@ def test_handle_create_subthreshold_grb_event(mock_get_upload_ext_skymap,
                                               mock_check_vectors,
                                               mock_create_event,
                                               mock_get_events):
-    text = read_binary(data, 'fermi_subthresh_grb_lowconfidence.xml')
+    text = resources.read_binary(data, 'fermi_subthresh_grb_lowconfidence.xml')
     external_triggers.handle_grb_gcn(payload=text)
     mock_create_event.assert_not_called()
-    text = read_binary(data, 'fermi_subthresh_grb_gcn.xml')
+    text = resources.read_binary(data, 'fermi_subthresh_grb_gcn.xml')
     external_triggers.handle_grb_gcn(payload=text)
     mock_get_events.assert_called_once_with(query=(
                                             'group: External pipeline: '
@@ -139,7 +148,7 @@ def test_handle_noise_fermi_event(mock_check_vectors,
                                   mock_get_events,
                                   mock_get_upload_external_skymap,
                                   filename):
-    text = read_binary(data, filename)
+    text = resources.read_binary(data, filename)
     external_triggers.handle_grb_gcn(payload=text)
     mock_get_events.assert_called_once_with(query=(
                                             'group: External pipeline: '
@@ -170,7 +179,7 @@ def test_handle_initial_fermi_event(mock_check_vectors,
                                     mock_get_events,
                                     mock_get_upload_external_skymap,
                                     mock_create_external_skymap):
-    text = read_binary(data, 'fermi_initial_grb_gcn.xml')
+    text = resources.read_binary(data, 'fermi_initial_grb_gcn.xml')
     external_triggers.handle_grb_gcn(payload=text)
     mock_get_events.assert_called_once_with(query=(
                                             'group: External pipeline: '
@@ -208,7 +217,7 @@ def test_handle_replace_grb_event(mock_get_events,
                                   mock_get_upload_external_skymap,
                                   mock_create_upload_external_skymap,
                                   filename):
-    text = read_binary(data, filename)
+    text = resources.read_binary(data, filename)
     external_triggers.handle_grb_gcn(payload=text)
     if 'subthresh' in filename:
         mock_replace_event.assert_not_called()
@@ -386,7 +395,7 @@ def test_handle_sog_manuscript_pipeline(mock_sog_paper_pipeline,
     'search': 'Supernova'})
 def test_handle_create_snews_event(mock_create_event,
                                    mock_upload, mock_json):
-    text = read_binary(data, 'snews_gcn.xml')
+    text = resources.read_binary(data, 'snews_gcn.xml')
     external_triggers.handle_snews_gcn(payload=text)
     mock_create_event.assert_called_once_with(filecontents=text,
                                               search='Supernova',
@@ -418,7 +427,7 @@ def test_handle_create_snews_event(mock_create_event,
 @patch('gwcelery.tasks.gracedb.replace_event.run')
 @patch('gwcelery.tasks.gracedb.get_events', return_value=[{'graceid': 'E1'}])
 def test_handle_replace_snews_event(mock_get_events, mock_replace_event):
-    text = read_binary(data, 'snews_gcn.xml')
+    text = resources.read_binary(data, 'snews_gcn.xml')
     external_triggers.handle_snews_gcn(payload=text)
     mock_replace_event.assert_called_once_with('E1', text)
 
-- 
GitLab