Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • emfollow/gwcelery
  • leo-singer/gwcelery
  • deep.chatterjee/gwcelery
  • michael-coughlin/gwcelery
  • brandon.piotrzkowski/gwcelery
  • geoffrey.mo/gwcelery
  • vinaya.valsan/gwcelery
  • patrick.godwin/gwcelery
  • john-veitch/gwcelery
  • roberto.depietri/gwcelery
  • veronica.villa/gwcelery
  • teresa.slaven-blair/gwcelery
  • cody.messick/gwcelery
  • sarah.antier/gwcelery
  • shreya.anand/gwcelery
  • ron.tapia/gwcelery
  • andrew.toivonen/gwcelery
  • adam-zadrozny/gwcelery
  • duncanmmacleod/gwcelery
  • sushant.sharma-chaudhary/gwcelery
  • manleong.chan/gwcelery
  • satyanarayan.raypitambarmohapatra/gwcelery
  • yu-kuang.chu/gwcelery
  • jacob.golomb/gwcelery
  • daniele.monteleone/gwcelery
  • albertcheng.zhang/gwcelery
  • colm.talbot/gwcelery
  • gaurav.waratkar/gwcelery
  • yun-jing.huang/gwcelery
29 results
Show changes
Commits on Source (6)
Showing
with 456 additions and 93 deletions
......@@ -4,6 +4,9 @@ Changelog
2.6.0 (unreleased)
------------------
- Add `HIGH_PROFILE` label to SSM preferred event and also log reason for
the label.
- Enabled SSM triggers and HasSSM source property
- Rework determining the preferred external event using a keyfunc method
......@@ -45,7 +48,6 @@ Changelog
- Don't download p-astro file for SSM alert canvas, since they are not required
by policy.
<<<<<<< HEAD
- Automatically rotate and compress log files to avoid running out of disk
space. Logs are rotated and compressed once per week and deleted after one
month.
......@@ -67,6 +69,10 @@ Changelog
- Drop support for Python 3.10, conforming to
`SPEC 0 — Minimum Supported Dependencies <https://scientific-python.org/specs/spec-0000/>`_.
- Reorganize RAVEN workflow to generalize IGWN alert sky map handler and
kafka JSON to VOEvent converter to be used by multiple pipelines in the
future.
2.5.2 "Cactus cat" (2024-11-18)
-------------------------------
......
......@@ -197,8 +197,8 @@ def _add_external_coinc_to_alert(alert_dict, superevent,
'ivorn': external_event['extra_attributes']['GRB']['ivorn'],
'observatory': external_event['pipeline'],
'search': external_event['search'],
'time_difference': round(superevent['t_0']
- external_event['gpstime'], 2),
'time_difference': round(external_event['gpstime'] -
superevent['t_0'], 2),
'time_coincidence_far': superevent['time_coinc_far'],
'time_sky_position_coincidence_far': superevent['space_coinc_far']
}
......
......@@ -220,15 +220,9 @@ def handle_grb_igwn_alert(alert):
* New event/superevent triggers a coincidence search with
:meth:`gwcelery.tasks.raven.coincidence_search`.
* When both a GW and GRB sky map are available during a coincidence,
indicated by the labels ``EM_READY`` and ``EXT_SKYMAP_READY``
respectively on the external event, this triggers the spacetime coinc
FAR to be calculated and a combined GW-GRB sky map is created using
:meth:`gwcelery.tasks.external_skymaps.create_combined_skymap`.
* Re-run sky map comparison if complete, and either the GW or GRB sky
map has been updated or if the preferred event changed.
* Re-check RAVEN publishing conditions if the GRB was previously
considered non-astrophycial but now should be considered.
* If other type of IGWN alert, pass to _handle_skymaps to decide whether
to re-run RAVEN pipeline based on labels or whether to add labels that
could start this process.
Parameters
----------
......@@ -313,10 +307,51 @@ def handle_grb_igwn_alert(alert):
raven.coincidence_search(
graceid, alert['object'], group=gw_group,
searches=searches, pipelines=[pipeline])
else:
_handle_skymaps(alert)
def _handle_skymaps(alert):
"""Parse an IGWN alert message related to superevents/GRB external triggers
and dispatch tasks related to re-running RAVEN pipeline due to new sky
maps.
Notes
-----
This IGWN alert message handler is triggered by a label associated with
completeness of skymaps or change in state, or if a sky map file is
uploaded:
* When both a GW and GRB sky map are available during a coincidence,
indicated by the labels ``EM_READY`` and ``EXT_SKYMAP_READY``
respectively on the external event, this triggers the spacetime coinc
FAR to be calculated and a combined GW-GRB sky map is created using
:meth:`gwcelery.tasks.external_skymaps.create_combined_skymap`.
* If new label indicates sky maps are available in the superevent,
apply to all associated external events.
* Re-run sky map comparison if complete, and also if either the GW or GRB
sky map has been updated or if the preferred event changed.
* Re-check RAVEN publishing conditions if the GRB was previously
considered non-astrophysical but now should be considered.
Parameters
----------
alert : dict
IGWN alert packet
"""
# Determine GraceDB ID
graceid = alert['uid']
# Define state variables
is_superevent = 'S' in graceid
is_external_event = alert['object'].get('group') == 'External'
is_coincidence = 'EM_COINC' in alert['object']['labels']
pe_ready = 'PE_READY' in alert['object']['labels']
# re-run raven pipeline and create combined sky map (if not a Swift event)
# when sky maps are available
elif alert['alert_type'] == 'label_added' and \
alert['object'].get('group') == 'External':
if alert['alert_type'] == 'label_added' and is_external_event:
if _skymaps_are_ready(alert['object'], alert['data']['name'],
'compare'):
# if both sky maps present and a coincidence, re-run RAVEN
......@@ -327,7 +362,7 @@ def handle_grb_igwn_alert(alert):
superevent = gracedb.get_superevent(superevent_id)
_relaunch_raven_pipeline_with_skymaps(
superevent, ext_event, graceid)
elif 'EM_COINC' in alert['object']['labels']:
elif is_coincidence:
# if not complete, check if GW sky map; apply label to external
# event if GW sky map
se_labels = gracedb.get_labels(alert['object']['superevent'])
......@@ -337,7 +372,7 @@ def handle_grb_igwn_alert(alert):
gracedb.create_label.si('EM_READY', graceid).delay()
# apply labels from superevent to external event to update state
# and trigger functionality requiring sky maps, etc.
elif alert['alert_type'] == 'label_added' and 'S' in graceid:
elif alert['alert_type'] == 'label_added' and is_superevent:
if 'SKYMAP_READY' in alert['object']['labels']:
# if sky map in superevent, apply label to all external events
# at the time
......@@ -364,21 +399,17 @@ def handle_grb_igwn_alert(alert):
# if new GW or external sky map after first being available, try to remake
# combine sky map and rerun raven pipeline
elif alert['alert_type'] == 'log' and \
'EM_COINC' in alert['object']['labels'] and \
is_coincidence and \
'fit' in alert['data']['filename'] and \
'flat' not in alert['data']['comment'].lower() and \
(alert['data']['filename'] !=
external_skymaps.COMBINED_SKYMAP_FILENAME_MULTIORDER):
superevent_id, external_id = _get_superevent_ext_ids(
graceid, alert['object'])
if 'S' in graceid:
superevent = alert['object']
else:
superevent = gracedb.get_superevent(alert['object']['superevent'])
external_event = alert['object']
# check if combined sky map already made, with the exception of Swift
# which will fail
if 'S' in graceid:
if is_superevent:
superevent = alert['object']
# Rerun for all eligible external events
for ext_id in superevent['em_events']:
external_event = gracedb.get_event(ext_id)
......@@ -388,6 +419,8 @@ def handle_grb_igwn_alert(alert):
superevent, external_event, graceid,
use_superevent_skymap=True)
else:
superevent = gracedb.get_superevent(alert['object']['superevent'])
external_event = alert['object']
if REQUIRED_LABELS_BY_TASK['compare'].issubset(
set(external_event['labels'])):
_relaunch_raven_pipeline_with_skymaps(
......@@ -395,11 +428,9 @@ def handle_grb_igwn_alert(alert):
# Rerun the coincidence FAR calculation if possible with combined sky map
# if the preferred event changes
# We don't want to run this logic if PE results are present
elif alert['alert_type'] == 'log' and \
'PE_READY' not in alert['object']['labels'] and \
'EM_COINC' in alert['object']['labels']:
elif alert['alert_type'] == 'log' and not pe_ready and is_coincidence:
new_log_comment = alert['data'].get('comment', '')
if 'S' in graceid and \
if is_superevent and \
new_log_comment.startswith('Updated superevent parameters: '
'preferred_event: '):
superevent = alert['object']
......@@ -411,10 +442,8 @@ def handle_grb_igwn_alert(alert):
_relaunch_raven_pipeline_with_skymaps(
superevent, external_event, graceid,
use_superevent_skymap=False)
elif alert['alert_type'] == 'label_removed' and \
alert['object'].get('group') == 'External':
if alert['data']['name'] == 'NOT_GRB' and \
'EM_COINC' in alert['object']['labels']:
elif alert['alert_type'] == 'label_removed' and is_external_event:
if alert['data']['name'] == 'NOT_GRB' and is_coincidence:
# if NOT_GRB is removed, re-check publishing conditions
superevent_id = alert['object']['superevent']
superevent = gracedb.get_superevent(superevent_id)
......@@ -495,7 +524,8 @@ def handle_targeted_kafka_alert(alert):
"""
# Convert alert to VOEvent format
# FIXME: This is required until native ingesting of kafka events in GraceDB
payload, pipeline, time, trig_id = _kafka_to_voevent(alert)
payload, pipeline, time, trig_id = \
_kafka_to_voevent(alert, 'SubGRBTargeted')
# Veto events that don't pass GRB FAR threshold
far_grb = alert['far']
......@@ -733,15 +763,17 @@ def _create_replace_external_event_and_skymap(
).delay()
def _kafka_to_voevent(alert):
"""Parse an alert sent via Kafka from a MOU partner in our joint
subthreshold targeted search and convert to an equivalent XML string
GCN VOEvent.
def _kafka_to_voevent(alert, search):
"""Parse an alert in JSON format sent via Kafka from public GCN Notices or
from a MOU partner in our joint subthreshold targeted search, converting
to an equivalent XML string VOEvent.
Parameters
----------
alert : dict
Kafka alert packet
search : list
External trigger search
Returns
-------
......@@ -750,48 +782,80 @@ def _kafka_to_voevent(alert):
"""
# Define basic values
pipeline = alert['mission']
pipeline = alert.get('mission')
if pipeline is None:
if 'instrument' not in alert:
raise ValueError("Alert does not contain pipeline information.")
elif alert['instrument'].lower() == 'wxt':
# FIXME: Replace with official GraceDB name once added
pipeline = 'EinsteinProbe'
# Get times, adding missing
start_time = alert['trigger_time']
alert_time = alert['alert_datetime']
far = alert['far']
duration = alert['rate_duration']
alert_time = alert.get('alert_datetime', start_time)
# If missing, add character onto end
if not start_time.endswith('Z'):
start_time += 'Z'
if not alert_time.endswith('Z'):
alert_time += 'Z'
# Try to get FAR is there
far = alert.get('far')
# Go through list of possible values for durations, 0. if no keys match
duration = 0.
duration_params = ['rate_duration', 'image_duration']
for param in duration_params:
if param in alert.keys():
duration = alert[param]
break
# Form ID out of given list
id = '_'.join(str(x) for x in alert['id'])
# Use central time since starting time is not well measured
central_time = \
Time(start_time, format='isot', scale='utc').to_value('gps') + \
.5 * duration
trigger_time = \
str(Time(central_time, format='gps', scale='utc').isot) + 'Z'
if search == 'SubGRBTargeted':
# Use central time since starting time is not well measured
central_time = \
Time(start_time, format='isot', scale='utc').to_value('gps') + \
.5 * duration
trigger_time = \
str(Time(central_time, format='gps', scale='utc').isot) + 'Z'
else:
trigger_time = start_time
# sky localization may not be available
ra = alert.get('ra')
dec = alert.get('dec')
# Try to get dec first then ra, None if both misssing
error = alert.get('dec_uncertainty')
if error is None:
error = alert.get('ra_uncertainty')
# Argument should be list if not None
# Go through list of possible values for error, None if no keys match
error = None
error_params = ['dec_uncertainty', 'ra_uncertainty', 'ra_dec_error']
for param in error_params:
if param in alert.keys():
error = alert[param]
break
# If argument is list, get value
if isinstance(error, list):
error = error[0]
# if any missing sky map info, set to zeros so will be ignored later
if ra is None or dec is None or error is None:
ra, dec, error = 0., 0., 0.
# Load template
fname = str(Path(__file__).parent /
'../tests/data/{}_subgrbtargeted_template.xml'.format(
pipeline.lower()))
fname = \
str(Path(__file__).parent /
f'../tests/data/{pipeline.lower()}_{search.lower()}_template.xml')
root = etree.parse(fname)
# Update template values
# Change ivorn to indicate this is a subthreshold targeted event
root.xpath('.')[0].attrib['ivorn'] = \
'ivo://lvk.internal/{0}#targeted_subthreshold-{1}'.format(
pipeline.lower(), trigger_time).encode()
# Update ID
root.find("./What/Param[@name='TrigID']").attrib['value'] = \
id.encode()
'ivo://lvk.internal/{0}#{1}-{2}'.format(
pipeline.lower(),
('targeted_subthreshold' if search == 'SubGRBTargeted'
else search.lower()),
trigger_time).encode()
# Change times to chosen time
root.find("./Who/Date").text = str(alert_time).encode()
......@@ -799,11 +863,27 @@ def _kafka_to_voevent(alert):
"ObservationLocation/AstroCoords/Time/TimeInstant/"
"ISOTime")).text = str(trigger_time).encode()
root.find("./What/Param[@name='FAR']").attrib['value'] = \
str(far).encode()
# Update ID and duration
# SVOM has separate template, use different paths
if pipeline == 'SVOM':
root.find(("./What/Group[@name='Svom_Identifiers']"
"/Param[@name='Burst_Id']")).attrib['value'] = \
id.encode()
root.find(("./What/Group[@name='Detection_Info']"
"/Param[@name='Timescale']")).attrib['value'] = \
str(duration).encode()
# Every other type uses similar format
else:
root.find("./What/Param[@name='TrigID']").attrib['value'] = \
id.encode()
root.find("./What/Param[@name='Integ_Time']").attrib['value'] = \
str(duration).encode()
root.find("./What/Param[@name='Integ_Time']").attrib['value'] = \
str(duration).encode()
if far is not None:
root.find("./What/Param[@name='FAR']").attrib['value'] = \
str(far).encode()
# Sky position
root.find(("./WhereWhen/ObsDataLocation/"
......
......@@ -81,7 +81,7 @@ def create_upload_external_event(gpstime, pipeline, ext_search):
# Return VOEvent for testing until GraceDB natively ingests kafka
# alerts
return external_triggers._kafka_to_voevent(alert)[0]
return external_triggers._kafka_to_voevent(alert, ext_search)[0]
# Otherwise modify respective VOEvent template
else:
......
......@@ -97,6 +97,20 @@ def create_label(label, graceid):
raise
@task(ignore_result=True, shared=False)
@catch_retryable_http_errors
def create_label_with_log(log_message, label, tags, superevent_id):
"""Create a label with a log for a superevent in GraceDB."""
try:
client.superevents[superevent_id].logs.create(
comment=log_message,
label=label,
tags=tags
)
except HTTPError:
raise
@task(ignore_result=True, shared=False)
@catch_retryable_http_errors
def remove_label(label, graceid):
......
......@@ -8,7 +8,7 @@ from ..util.tempfile import NamedTemporaryFile
from . import gracedb
@app.task(shared=False)
@app.task(ignore_result=True, shared=False)
def check_high_profile(skymap, em_bright,
p_astro, superevent):
superevent_id = superevent['superevent_id']
......@@ -16,7 +16,7 @@ def check_high_profile(skymap, em_bright,
# RAVEN_ALERT HIGH_PROFILE is implemented in raven.py
# Checking if the label is applied beforehand
if 'HIGH_PROFILE' in superevent['labels']:
return "HIGH_PROFILE already applied"
return # HIGH_PROFILE already applied
# low-far unmodelled burst condition
far_list = []
......@@ -30,16 +30,29 @@ def check_high_profile(skymap, em_bright,
if far_list_sorted[0]["group"] == "Burst" and \
far_list_sorted[0]["search"] != "BBH":
gracedb.create_label.si(
'HIGH_PROFILE', superevent_id).delay()
return "Event with the lowest FAR is a Burst event. Applying label"
gracedb.create_label_with_log(
log_message='Superevent labeled '
'<span color="red">HIGH_PROFILE</span> '
'since event with lowest FAR is a Burst event.',
label='HIGH_PROFILE',
tags=['em_follow'],
superevent_id=superevent_id)
return
# annotation number condition
preferred_event = superevent['preferred_event_data']
if preferred_event["search"] == "SSM":
gracedb.create_label_with_log(
log_message='Superevent labeled '
'<span color="red">HIGH_PROFILE</span> '
'since preferred event is from SSM search.',
label='HIGH_PROFILE',
tags=['em_follow'],
superevent_id=superevent_id)
return
if preferred_event["group"] == "CBC":
em_bright_dict = json.loads(em_bright)
has_remnant = em_bright_dict['HasRemnant']
pastro_dict = json.loads(p_astro)
p_bns = pastro_dict['BNS']
p_terr = pastro_dict['Terrestrial']
......@@ -50,10 +63,41 @@ def check_high_profile(skymap, em_bright,
cl = 90
result = crossmatch(gw_skymap, contours=[cl / 100])
sky_area = result.contour_areas[0]
# This is commented out while we figure out the distance cutoff
# is_far_away = not (gw_skymap.meta.get('distmean', np.nan) < 2000)
if p_terr < 0.5:
if (p_bns > 0.1 or p_nsbh > 0.1 or has_remnant > 0.1 or sky_area < 100): # noqa: E501
gracedb.create_label.si(
'HIGH_PROFILE', superevent_id).delay()
return "Annotations condition satisfied. Applying label"
if p_bns > 0.1:
gracedb.create_label_with_log(
log_message='Superevent labeled '
'<span color="red">HIGH_PROFILE</span> since p_BNS > 10%.', # noqa: E501
label='HIGH_PROFILE',
tags=['em_follow'],
superevent_id=superevent_id)
return
elif p_nsbh > 0.1:
gracedb.create_label_with_log(
log_message='Superevent labeled '
'<span color="red">HIGH_PROFILE</span> since p_NSBH > 10%.', # noqa: E501
label='HIGH_PROFILE',
tags=['em_follow'],
superevent_id=superevent_id)
return
elif has_remnant > 0.1:
gracedb.create_label_with_log(
log_message='Superevent labeled '
'<span color="red">HIGH_PROFILE</span> since '
'p_HasRemnant > 10%.',
label='HIGH_PROFILE',
tags=['em_follow'],
superevent_id=superevent_id)
return
elif sky_area < 100:
gracedb.create_label_with_log(
log_message='Superevent labeled '
'<span color="red">HIGH_PROFILE</span> since area of '
'90% confidence level in the skymap is < 100 sq.deg.',
label='HIGH_PROFILE',
tags=['em_follow'],
superevent_id=superevent_id)
return
return "No conditions satisfied. Skipping"
<?xml version='1.0' encoding='UTF-8'?>
<voe:VOEvent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:voe="http://www.ivoa.net/xml/VOEvent/v2.0" xsi:schemaLocation="http://www.ivoa.net/xml/VOEvent/v2.0 http://www.ivoa.net/xml/VOEvent/VOEvent-v2.0.xsd" version="2.0" role="test" ivorn="ivo://lvk.internal/einsteinprobe#grb-2024-08-01T09:07:13.799Z">
<Who>
<Description>VOEvent created with voevent-parse, version 1.0.3. See https://github.com/timstaley/voevent-parse for details.</Description>
<AuthorIVORN>ivo://eintseinprobe</AuthorIVORN>
<Date>2024-08-01T09:07:13.799Z</Date>
<Author>
<shortName>EinsteinProbe/WXT</shortName>
<contactName>LVK-internal</contactName>
<contactEmail>LVK-internal</contactEmail>
</Author>
</Who>
<What>
<Param name="TrigID" value="01709015181" ucd="meta.id"/>
<Param name="Integ_Time" value="0.0" unit="sec" ucd="time.interval"/>
</What>
<WhereWhen>
<ObsDataLocation>
<ObservatoryLocation id="GEOLUN"/>
<ObservationLocation>
<AstroCoordSystem id="UTC-FK5-GEO"/>
<AstroCoords coord_system_id="UTC-FK5-GEO">
<Time unit="s">
<TimeInstant>
<ISOTime>2024-08-01T09:07:13.799Z</ISOTime>
</TimeInstant>
</Time>
<Position2D unit="deg">
<Name1>RA</Name1>
<Name2>Dec</Name2>
<Value2>
<C1>345.134</C1>
<C2>32.607999999</C2>
</Value2>
<Error2Radius>0.05071889</Error2Radius>
</Position2D>
</AstroCoords>
</ObservationLocation>
</ObsDataLocation>
</WhereWhen>
<How>
<Description>EinsteinProbe, WXT Instrument</Description>
</How>
</voe:VOEvent>
{
"$schema": "https://gcn.nasa.gov/schema/v4.1.0/gcn/notices/einstein_probe/wxt/alert.schema.json",
"instrument": "WXT",
"trigger_time": "2024-08-01T09:07:13.799Z",
"id": [
"01709015181"
],
"ra": 345.134,
"dec": 32.607999999,
"ra_dec_error": 0.05071889,
"image_energy_range": [
0.5,
4
],
"net_count_rate": 0.06,
"image_snr": 10.9,
"additional_info": "The net count rate is derived from an accumulated image (up to 20 min) in 0.5-4 keV, assuming a constant flux. However, it can be significantly lower than the actual count rate of a burst with a duration much shorter than 20 min."
}
\ No newline at end of file
{
"$schema": "https://gcn.nasa.gov/schema/main/gcn/notices/svom/eclairs/wakeup.schema.json",
"mission": "SVOM",
"instrument": "ECLAIRs",
"alert_datetime": "2024-02-22T08:51:55",
"alert_tense": "test",
"alert_type": "initial",
"notice_level": "N1e",
"id": ["sb24022203"],
"image_snr": 25.67,
"image_duration": 0.0,
"image_energy_range": [4, 20],
"trigger_type": "Count_Rate",
"slew_status": "not_requested",
"trigger_time": "2024-02-22T08:51:31.320000",
"ra": 143.2478,
"dec": -68.0289,
"uncertainty_shape": "circle",
"ra_uncertainty": [0.1],
"p_astro": 1,
"additional_info": "N1e notice from SVOM ECLAIRs",
"data_archive_page": "https://www.svom.eu/en/telescope-eclairs-en"
}
\ No newline at end of file
No preview for this file type
<?xml version='1.0' encoding='UTF-8'?>
<voe:VOEvent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:voe="http://www.ivoa.net/xml/VOEvent/v2.0" xsi:schemaLocation="http://www.ivoa.net/xml/VOEvent/v2.0 http://www.ivoa.net/xml/VOEvent/VOEvent-v2.0.xsd" version="2.0" role="observation" ivorn="ivo://lvk.internal/svom#grb-2024-02-22T08:51:31.320000Z">
<Who>
<AuthorIVORN>ivo://org.svom/FSC</AuthorIVORN>
<Date>2024-02-22T08:51:55Z</Date>
<Author><title>French Science Center</title>
<shortName>FSC</shortName>
<contactEmail>svom-contact@cea.fr</contactEmail>
</Author>
</Who>
<What>
<Param name="Packet_Type" value="576" ucd="meta.id"/>
<Param name="Pkt_Ser_Num" value="1" ucd="meta.id"/>
<Param name="Instrument" value="ECLAIRs" ucd="instr"/>
<Param name="Swift_Trig_Id" value="1213880" ucd="meta.id"/>
<Group name="Svom_Identifiers">
<Param name="Notice_Level" value="N1e" ucd="meta.id"/>
<Param name="Burst_Id" value="sb24022203" ucd="meta.id"/>
</Group>
<Group name="Detection_Info">
<Param name="SNR" value="200.00" unit="sigma" ucd="stat.snr"/>
<Param name="Timescale" value="0.0" unit="s" ucd="time.interval"/>
<Param name="Lower_Energy_Bound" value="4" unit="keV" ucd="em.energy"/>
<Param name="Upper_Energy_Bound" value="20" unit="keV" ucd="em.energy"/>
<Param name="Trigger_Type" value="Count_Rate" ucd="instr.param"/>
</Group>
<Group name="Target_Info">
<Param name="Galactic_Lon" value="62.11" unit="deg" ucd="pos.galactic.lon"/>
<Param name="Galactic_Lat" value="4.57" unit="deg" ucd="pos.galactic.lat"/>
<Param name="Moon_Angle" value="87.67" unit="deg" ucd="pos.angDistance"/>
<Param name="Sun_Angle" value="53.07" unit="deg" ucd="pos.angDistance"/>
</Group>
<Group name="Satellite_Info">
<Param name="Slew_Status" value="not_requested" ucd="meta.code.status"/>
<Param name="Attitude_Ra" value="288.07" unit="deg" ucd="instr.param"/>
<Param name="Attitude_Dec" value="28.84" unit="deg" ucd="instr.param"/>
<Param name="Attitude_Roll" value="360.00" unit="deg" ucd="instr.param"/>
<Param name="Sat_Longitude" value="0.00" unit="deg" ucd="pos.earth.lon"/>
<Param name="Sat_Latitude" value="90.00" unit="deg" ucd="pos.earth.lat"/>
<Param name="Sat_Altitude" value="-6356.75" unit="km" ucd="pos.earth.altitude"/>
</Group>
</What>
<WhereWhen>
<ObsDataLocation>
<ObservatoryLocation id="GEOLEO"/>
<ObservationLocation>
<AstroCoordSystem id="UTC-ICRS-GEO"/>
<AstroCoords coord_system_id="UTC-ICRS-GEO">
<Time unit="s">
<TimeInstant>
<ISOTime>2024-02-22T08:51:31.320000Z</ISOTime>
</TimeInstant>
</Time>
<Position2D unit="deg">
<Name1>RA</Name1>
<Name2>Dec</Name2>
<Value2>
<C1>143.2478</C1>
<C2>-68.0289</C2>
</Value2>
<Error2Radius>0.1</Error2Radius>
</Position2D>
</AstroCoords>
</ObservationLocation>
</ObsDataLocation>
</WhereWhen>
<Why>
<Inference probability="1.00">
<Name>Swift Trigger_Num 1213880</Name>
<Concept>process.variation.burst;em.gamma
</Concept>
</Inference>
</Why>
<How>
<Description>N1E NOTICE DERIVED FROM SWIFT TRIGGER #1213880</Description>
<Reference uri="https://gcn.gsfc.nasa.gov/other/1213880.swift"/>
</How>
</voe:VOEvent>
......@@ -1009,3 +1009,35 @@ def test_handle_mdc_sn_creation(mock_raven_coincidence_search,
mock_raven_coincidence_search.assert_called_once_with(
graceid, alert['object'], group='Burst', searches=['MDC'],
se_searches=['MDC'], pipelines=['SNEWS'])
@pytest.mark.parametrize(
'kafka_path,voevent_path,search',
[['kafka_alert_fermi.json',
'fermi_subgrbtargeted_template.xml',
'SubGRBTargeted'],
['kafka_alert_swift.json',
'swift_subgrbtargeted_template.xml',
'SubGRBTargeted'],
['kafka_alert_svom_wakeup.json',
'svom_grb_template.xml',
'GRB'],
['kafka_alert_einteinprobe.json',
'einsteinprobe_grb_template.xml',
'GRB']])
def test_kafka_to_voevent(kafka_path, voevent_path, search):
voevent_text = read_binary(data, voevent_path)
alert = read_json(data, kafka_path)
voevent_result, pipeline, time, id = \
external_triggers._kafka_to_voevent(alert, search)
assert voevent_result == voevent_text
def test_kafka_to_voevent_empty():
"""Test that giving a file with no pipeline/instrument info gives a
ValueError."""
with pytest.raises(ValueError):
external_triggers._kafka_to_voevent({}, 'GRB')
......@@ -48,6 +48,15 @@ def test_create_label(mock_gracedb):
'label')
@patch('gwcelery.tasks.gracedb.client')
def test_create_label_with_log(mock_gracedb):
gracedb.create_label_with_log('log_message', 'label', ['tag'], 'graceid')
mock_gracedb.superevents['graceid'].logs.create.assert_called_once_with(
comment='log_message',
label='label',
tags=['tag'])
@patch('gwcelery.tasks.gracedb.client')
def test_remove_label(mock_gracedb):
gracedb.remove_label('label', 'graceid')
......
......@@ -16,11 +16,12 @@ skymap_large = read_binary(data, 'MS220722v_bayestar.multiorder.fits')
# 3. p_BNS check ---> True
# 4. p_NSBH check ---> True
# 5. skymap check ---> True
# 6. Simple BBH ---> False
# 7. Burst but low far ---> False
# 8. High p-terrestrial ---> False
# 9. Burst BBH low far ---> False
# 10. HIGH_PROFILE_applied-> False
# 6. SSM preferred ---> True
# 7. Simple BBH ---> False
# 8. Burst but low far ---> False
# 9. High p-terrestrial ---> False
# 10. Burst BBH low far ---> False
# 11. HIGH_PROFILE_applied-> False
def get_event(graceid):
......@@ -60,6 +61,15 @@ def get_event(graceid):
'far': 1e-10,
'gpstime': 1234,
}
elif graceid == 'G468':
event = {
'group': 'CBC',
'pipeline': 'gstlal',
'search': 'SSM',
'graceid': graceid,
'far': 1e-10,
'gpstime': 1234,
}
return event
......@@ -85,6 +95,10 @@ def get_event(graceid):
{'HasNS': 0.0, 'HasRemnant': 0.0, 'HasMassGap': 0.0},
{"BNS": 0.0, "NSBH": 0.0, "BBH": 0.9, "Terrestrial": 0.1},
skymap_small, True],
[{'labels': [], 'gw_events': ['G123', 'G468']},
{'HasNS': 0.0, 'HasSSM': 1.0, 'HasMassGap': 0.0},
{"BNS": 0.0, "NSBH": 0.0, "BBH": 0.9, "Terrestrial": 0.1},
skymap_large, True],
[{'labels': [], 'gw_events': ['G123']},
{'HasNS': 0.0, 'HasRemnant': 0.0, 'HasMassGap': 0.0},
{"BNS": 0.0, "NSBH": 0.0, "BBH": 1.0, "Terrestrial": 0.0},
......@@ -110,18 +124,20 @@ def test_high_profile(monkeypatch, superevent, embright,
pastro, skymap, result):
embright = json.dumps(embright)
pastro = json.dumps(pastro)
superevent.update({'superevent_id': 'S123',
'preferred_event_data': get_event('G123')})
mock_create_label = Mock()
monkeypatch.setattr('gwcelery.tasks.gracedb.create_label.run',
mock_create_label)
if 'G468' in superevent['gw_events']:
superevent.update({'superevent_id': 'S123',
'preferred_event_data': get_event('G468')})
else:
superevent.update({'superevent_id': 'S123',
'preferred_event_data': get_event('G123')})
mock_create_label_with_log = Mock()
monkeypatch.setattr('gwcelery.tasks.gracedb.create_label_with_log.run',
mock_create_label_with_log)
monkeypatch.setattr('gwcelery.tasks.gracedb.get_event.run',
get_event)
rrt_utils.check_high_profile(skymap, embright,
pastro, superevent)
if result is True:
mock_create_label.assert_called_once_with(
"HIGH_PROFILE", "S123"
)
mock_create_label_with_log.assert_called_once()
elif result is False:
mock_create_label.assert_not_called()
mock_create_label_with_log.assert_not_called()
......@@ -6178,4 +6178,4 @@ test = ["fastavro", "pytest-celery", "pytest-cov", "pytest-flask", "pytest-socke
[metadata]
lock-version = "2.0"
python-versions = "^3.11,<3.13"
content-hash = "ab6da5bd2cc8068e8b9c57b9b6fb3f190ac59fd73a7c602fa09623cf94c0508f"
content-hash = "df629acad14fab6d6a52793316001863b00df064065763ccb0eef8a242a14404"
......@@ -69,6 +69,7 @@ gwpy = ">=3.0.8" # https://git.ligo.org/emfollow/gwcelery/-/issues/183
GWSkyNet = "2.5.1" # https://git.ligo.org/manleong.chan/gwskynet/-/issues/5
healpy = "*"
hop-client = ">=0.7.0" # https://github.com/scimma/hop-client/pull/176
hpmoc = ">=1.0.0"
igwn-alert = ">=0.6.3" # https://git.ligo.org/computing/igwn-alert/client/-/merge_requests/30
igwn-gwalert-schema = "^1.0.0"
imapclient = "*"
......@@ -116,8 +117,6 @@ pytest-cov = {version="*", optional=true}
pytest-flask = {version="*", optional=true}
pytest-socket = {version="*", optional=true}
ligo-rrt-chat = ">=0.1.5" # https://git.ligo.org/computing/sccb/-/issues/1562"
hpmoc = ">=1.0.0"
gwskynet = "^2.3.0"
[tool.poetry.extras]
doc = ["pep517", "sphinx"]
......