From 22ad490aa53056f950155a602fbc5fc872753f08 Mon Sep 17 00:00:00 2001 From: Leo Singer Date: Tue, 16 Jul 2024 06:42:07 -0400 Subject: [PATCH 01/10] Note: Squashed a bunch of commits and cleaned up commit history message Explicit int conversion removed MAXI_UNKNOWN conversion Removed GECAM_FLT and GECAM_GND conversion Added documentation and changed function name reformatted file deleted files --- .../notices/CALET_GBM_FLT_LC/__init__.py | 51 +++++++++++++++++++ .../notices/CALET_GBM_FLT_LC/example.json | 28 ++++++++++ .../notices/SWIFT_BAT_GRB_POS_ACK/__init__.py | 12 +---- .../SWIFT_BAT_GRB_POS_ACK/example.json | 2 +- gcn_classic_to_json/utils.py | 28 ++++++++++ 5 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py create mode 100644 gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json create mode 100644 gcn_classic_to_json/utils.py diff --git a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py new file mode 100644 index 0000000..f7445f2 --- /dev/null +++ b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py @@ -0,0 +1,51 @@ +import numpy as np + +from ... import utils + + +def parse(bin): + if (bin[0] != 160) and (bin[39] != 10): + return + + if np.all(bin[1:4]) and bin[12] and np.all(bin[13:16]) and np.all(bin[20:29]): + pass + + lat, lon = bin[16:17].view(">i2") + + trig_id_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) + trig_id_descriptions = { + 5: "This is not a real event.\n", + 29: "There was a temporal coincidence with another event.\n", + 30: "This is a test submission.\n", + } + comments = "".join( + [val for (key, val) in trig_id_descriptions.items() if trig_id_bits[key] == 1] + ) + + detector_options = ["on", "triggered"] + detectors_bits = np.flip(np.unpackbits(bin[19:20].view(dtype="u1")))[:3] + detectors_status = [detector_options[bit] for bit in detectors_bits] + detectors = dict(zip(["HXM1", "HMX2", "SGM"], detectors_status)) + + return { + "mission": "CALET", + "instrument": "GBM", + # "alert_type" : "initial", # does not exist in the binaries + # "record_number" = 1, # does not exist in binaries + "id": [bin[4]], + "messenger": "EM", + "trigger_time": utils.datetime_to_iso8601(bin[5], bin[6]), + "trigger_type": "rate", + "rate_energy_range": np.flip(bin[17:18].view(">i2")), + "rate_snr": bin[9] * 1e-2, + "rate_duration": bin[10] * 1e-2, + "background_duration": bin[11] * 1e-2, + "ra": bin[7] * 1e-4, + "dec": bin[8] * 1e-4, + "latitude": lat * 1e-2, + "longitude": lon * 1e-2, + "detector_status": detectors, + "url": "http://cgbm.calet.jp/cgbm_trigger/flight/" + + utils.binary_to_string(bin[29:39]), + "additional_info": comments if comments else None, + } diff --git a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json new file mode 100644 index 0000000..20e08b4 --- /dev/null +++ b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json @@ -0,0 +1,28 @@ +{ + "mission": "CALET", + "instrument": "GBM", + "id": [ + 1399729386 + ], + "messenger": "EM", + "trigger_time": "2024-05-14T13:49:42.620Z", + "trigger_type": "rate", + "rate_energy_range": [ + 40, + 230 + ], + "rate_snr": 8.3, + "rate_duration": 4.0, + "background_duration": 16.0, + "ra": 193.85000000000002, + "dec": 50.359, + "latitude": 50.22, + "longitude": 113.87, + "detector_status": { + "HXM1": "on", + "HMX2": "on", + "SGM": "triggered" + }, + "url": "http://cgbm.calet.jp/cgbm_trigger/flight/index.html", + "additional_info": null +} diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py index c63ef56..16e9129 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py @@ -1,17 +1,9 @@ -from astropy.time import Time - -# Zero point for Truncated Julian Day according to -# https://en.wikipedia.org/wiki/Julian_day. -TJD0 = (2440000, 0.5) +from ... import utils def parse(bin): return { - "trigger_time": Time( - bin[5] + TJD0[0], - bin[6] / 8640000 + TJD0[1], - format="jd", - ).isot, + "trigger_time": utils.tjd_to_jd(bin[5], bin[6]), "ra": 1e-4 * bin[7], "dec": 1e-4 * bin[8], "ra_dec_error": 1e-4 * bin[11], diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json index 9202286..9421539 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json @@ -1,5 +1,5 @@ { - "trigger_time": "2024-05-11T18:06:53.220", + "trigger_time": "2024-05-11 18:06:53.220Z", "ra": 336.66450000000003, "dec": 8.5135, "ra_dec_error": 0.05 diff --git a/gcn_classic_to_json/utils.py b/gcn_classic_to_json/utils.py new file mode 100644 index 0000000..38c9457 --- /dev/null +++ b/gcn_classic_to_json/utils.py @@ -0,0 +1,28 @@ +from astropy.time import Time +import numpy as np + + +def datetime_to_iso8601(date, time): + """Converts time to ISO 8601 format. + + The function convert datetime into the ISO 8601 format from + Truncated Julian Date by first converting it to Julian Date. + + Parameters + ---------- + date : int + Date must be in Truncated Julian Date format. + time : int + Time of day must in Seconds of Day format. + + Returns + ------- + string + returns datetime in ISO8601 format. + + Notes + ----- + The zero point for Truncated Julian Day is given in https://en.wikipedia.org/wiki/Julian_day. + """ + TJD0 = (2440000, 0.5) + return Time(date + TJD0[0], time / 8640000 + TJD0[1], format="jd").isot + "Z" From eb667a491e9596a286a14551a2321a33107c371b Mon Sep 17 00:00:00 2001 From: Athish Thiruvengadam Date: Tue, 6 Aug 2024 14:03:55 -0400 Subject: [PATCH 02/10] reformatting --- .../notices/CALET_GBM_FLT_LC/__init__.py | 2 -- .../notices/SWIFT_BAT_GRB_POS_ACK/__init__.py | 2 +- .../SWIFT_BAT_GRB_POS_ACK/example.json | 2 +- gcn_classic_to_json/test/test_notices.py | 2 +- gcn_classic_to_json/utils.py | 31 +++++++++++++++++-- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py index f7445f2..82a8aaa 100644 --- a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py +++ b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py @@ -30,8 +30,6 @@ def parse(bin): return { "mission": "CALET", "instrument": "GBM", - # "alert_type" : "initial", # does not exist in the binaries - # "record_number" = 1, # does not exist in binaries "id": [bin[4]], "messenger": "EM", "trigger_time": utils.datetime_to_iso8601(bin[5], bin[6]), diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py index 16e9129..a7c8b60 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py @@ -3,7 +3,7 @@ def parse(bin): return { - "trigger_time": utils.tjd_to_jd(bin[5], bin[6]), + "trigger_time": utils.datetime_to_iso8601(bin[5], bin[6]), "ra": 1e-4 * bin[7], "dec": 1e-4 * bin[8], "ra_dec_error": 1e-4 * bin[11], diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json index 9421539..d493ebb 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json @@ -1,5 +1,5 @@ { - "trigger_time": "2024-05-11 18:06:53.220Z", + "trigger_time": "2024-05-11T18:06:53.220Z", "ra": 336.66450000000003, "dec": 8.5135, "ra_dec_error": 0.05 diff --git a/gcn_classic_to_json/test/test_notices.py b/gcn_classic_to_json/test/test_notices.py index fb85aee..c8fa286 100644 --- a/gcn_classic_to_json/test/test_notices.py +++ b/gcn_classic_to_json/test/test_notices.py @@ -67,7 +67,7 @@ def mock_frombuffer(*args, **kwargs): if not used.all(): raise AssertionError( - f'All fields in the binary packet must be used. The fields with the following indices were unused: {' '.join(np.flatnonzero(~used).astype(str))}' + f"All fields in the binary packet must be used. The fields with the following indices were unused: {' '.join(np.flatnonzero(~used).astype(str))}" ) diff --git a/gcn_classic_to_json/utils.py b/gcn_classic_to_json/utils.py index 38c9457..362a356 100644 --- a/gcn_classic_to_json/utils.py +++ b/gcn_classic_to_json/utils.py @@ -1,11 +1,11 @@ -from astropy.time import Time import numpy as np +from astropy.time import Time def datetime_to_iso8601(date, time): """Converts time to ISO 8601 format. - The function convert datetime into the ISO 8601 format from + The function converts input into the ISO 8601 format from Truncated Julian Date by first converting it to Julian Date. Parameters @@ -26,3 +26,30 @@ def datetime_to_iso8601(date, time): """ TJD0 = (2440000, 0.5) return Time(date + TJD0[0], time / 8640000 + TJD0[1], format="jd").isot + "Z" + + +def binary_to_string(binary): + """Converts a binary array to a ASCII-string. + + The function converts each field encoded as a 4-byte integer into + four 1-byte integers and then to their corresponding ASCII value. + + Parameters + ---------- + binary : array-like + A array for binary values encoded as 4-byte integers. + + Returns + ------- + string: + returns the corresponding ASCII string. + + Notes: + ------ + The strings in the binary packets seem to encoded little-endian. + """ + bits_array = np.asarray(binary, dtype=" Date: Tue, 6 Aug 2024 17:35:30 -0400 Subject: [PATCH 03/10] Added code to ignore unused binary fields. --- .../notices/CALET_GBM_FLT_LC/__init__.py | 16 ++++++++++------ .../notices/CALET_GBM_FLT_LC/example.json | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py index 82a8aaa..5b1666d 100644 --- a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py +++ b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py @@ -4,11 +4,15 @@ def parse(bin): - if (bin[0] != 160) and (bin[39] != 10): - return - - if np.all(bin[1:4]) and bin[12] and np.all(bin[13:16]) and np.all(bin[20:29]): - pass + assert bin[12] == 0, "Unused. According to docs: 'Always 0 for FLT_LC'" + bin[ + 1 + ] # Unused. According to docs: 'serial number of the packet'. Generally set to 1. + bin[2] # Unused. According to docs: 'hopcount item is defunct'. + bin[ + 3 + ] # Unused. According to docs: 'seconds of day when packet was created'. Cannot use without date that the packet. + bin[20:29] # Unused. According to docs: '36 bytes for the future' lat, lon = bin[16:17].view(">i2") @@ -43,7 +47,7 @@ def parse(bin): "latitude": lat * 1e-2, "longitude": lon * 1e-2, "detector_status": detectors, - "url": "http://cgbm.calet.jp/cgbm_trigger/flight/" + "url": f"http://cgbm.calet.jp/cgbm_trigger/flight/{bin[4]}" + utils.binary_to_string(bin[29:39]), "additional_info": comments if comments else None, } diff --git a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json index 20e08b4..faf6ddd 100644 --- a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json +++ b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json @@ -23,6 +23,6 @@ "HMX2": "on", "SGM": "triggered" }, - "url": "http://cgbm.calet.jp/cgbm_trigger/flight/index.html", + "url": "http://cgbm.calet.jp/cgbm_trigger/flight/1399729386index.html", "additional_info": null } From 995b03ebb52b19519343f7880637311bbf4b5df9 Mon Sep 17 00:00:00 2001 From: Athish Thiruvengadam Date: Tue, 6 Aug 2024 17:46:21 -0400 Subject: [PATCH 04/10] fixed URL and refactored utils.py --- .../notices/CALET_GBM_FLT_LC/__init__.py | 11 ++++------- .../notices/CALET_GBM_FLT_LC/example.json | 2 +- gcn_classic_to_json/utils.py | 19 +++++++++++-------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py index 5b1666d..5229dae 100644 --- a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py +++ b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py @@ -5,13 +5,10 @@ def parse(bin): assert bin[12] == 0, "Unused. According to docs: 'Always 0 for FLT_LC'" - bin[ - 1 - ] # Unused. According to docs: 'serial number of the packet'. Generally set to 1. + bin[1] # Unused. According to docs: 'Generally set to 1.' bin[2] # Unused. According to docs: 'hopcount item is defunct'. - bin[ - 3 - ] # Unused. According to docs: 'seconds of day when packet was created'. Cannot use without date that the packet. + bin[3] # Unused. According to docs: 'seconds of day when packet was created'. + bin[13:16] # Unused. According to docs: '12 bytes for the future' bin[20:29] # Unused. According to docs: '36 bytes for the future' lat, lon = bin[16:17].view(">i2") @@ -47,7 +44,7 @@ def parse(bin): "latitude": lat * 1e-2, "longitude": lon * 1e-2, "detector_status": detectors, - "url": f"http://cgbm.calet.jp/cgbm_trigger/flight/{bin[4]}" + "url": f"http://cgbm.calet.jp/cgbm_trigger/flight/{bin[4]}/" + utils.binary_to_string(bin[29:39]), "additional_info": comments if comments else None, } diff --git a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json index faf6ddd..2e26abf 100644 --- a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json +++ b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/example.json @@ -23,6 +23,6 @@ "HMX2": "on", "SGM": "triggered" }, - "url": "http://cgbm.calet.jp/cgbm_trigger/flight/1399729386index.html", + "url": "http://cgbm.calet.jp/cgbm_trigger/flight/1399729386/index.html", "additional_info": null } diff --git a/gcn_classic_to_json/utils.py b/gcn_classic_to_json/utils.py index 362a356..f643ed8 100644 --- a/gcn_classic_to_json/utils.py +++ b/gcn_classic_to_json/utils.py @@ -31,8 +31,9 @@ def datetime_to_iso8601(date, time): def binary_to_string(binary): """Converts a binary array to a ASCII-string. - The function converts each field encoded as a 4-byte integer into - four 1-byte integers and then to their corresponding ASCII value. + The function converts `binary` into a C-style string, + flips the position of every 4 bytes, strips excess null characters + and then converts the result into ASCII characters. Parameters ---------- @@ -46,10 +47,12 @@ def binary_to_string(binary): Notes: ------ - The strings in the binary packets seem to encoded little-endian. + The strings in the binary packets look like they were accidentally byte-swapped. """ - bits_array = np.asarray(binary, dtype=" Date: Wed, 7 Aug 2024 12:00:16 -0400 Subject: [PATCH 05/10] Moved pkt_sernum, pkt_hop_cnt and pkt_sod to notices/__init__.py --- gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py | 3 --- gcn_classic_to_json/notices/__init__.py | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py index 5229dae..a8bfd25 100644 --- a/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py +++ b/gcn_classic_to_json/notices/CALET_GBM_FLT_LC/__init__.py @@ -5,9 +5,6 @@ def parse(bin): assert bin[12] == 0, "Unused. According to docs: 'Always 0 for FLT_LC'" - bin[1] # Unused. According to docs: 'Generally set to 1.' - bin[2] # Unused. According to docs: 'hopcount item is defunct'. - bin[3] # Unused. According to docs: 'seconds of day when packet was created'. bin[13:16] # Unused. According to docs: '12 bytes for the future' bin[20:29] # Unused. According to docs: '36 bytes for the future' diff --git a/gcn_classic_to_json/notices/__init__.py b/gcn_classic_to_json/notices/__init__.py index 3185c64..a7d388b 100644 --- a/gcn_classic_to_json/notices/__init__.py +++ b/gcn_classic_to_json/notices/__init__.py @@ -20,6 +20,9 @@ def parse(key, value): ints = _frombuffer(value) assert len(ints) == 40 assert ints[0] == NoticeType[key], "Field 0 must equal the notice type" + ints[1] # Unused. According to docs: 'Generally set to 1.' + ints[2] # Unused. According to docs: 'hopcount item is defunct'. + ints[3] # Unused. According to docs: 'seconds of day when packet was created'. assert ( ints[-1] == np.asarray("\0\0\0\n", dtype="c").view(">i4")[0] ), "Field 39 must be a newline" From 10e0d808f81837277c57487cd63c4d13fcc32b4d Mon Sep 17 00:00:00 2001 From: Athish Thiruvengadam Date: Wed, 7 Aug 2024 14:52:15 -0400 Subject: [PATCH 06/10] swift bat conversion initial commit --- .../notices/SWIFT_BAT_GRB_POS_ACK/__init__.py | 69 +++++++++++++++++++ .../SWIFT_BAT_GRB_POS_ACK/example.json | 26 ++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py index a7c8b60..a5d2c3a 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py @@ -1,10 +1,79 @@ +import numpy as np + from ... import utils def parse(bin): + bin[15] # Unused. According to docs: '4 bytes for the future' + bin[19] # Unused. Flags are either internal or equivalent to bin[18] + bin[26:36] # Unused. According to docs: '40 bytes for the future' + bin[36] # Unused. Flags Equivalent to bin[18] + bin[38] # Unused. Sun/Moon parameters + + integ_time = bin[14] * 16 / 1000 + + lat, lon = bin[16:17].view(">i2") + + soln_status_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) + + flag_descriptions = { + 0: "A point source was found.\n", + 1: "It is a GRB.\n", + 2: "It is an interesting src.\n", + 3: "It is in the flight catalog.\n", + 5: "It is definitely not a GRB.\n", + 6: "It is probably not a GRB or Transient(hi bkg level).\n", + 7: "It is probably not a GRB or Transient(low image significance; < 7).\n", + 8: "It is in the ground catalog.\n", + 9: "It is probably not a GRB or Transient(negative bkg slop).\n", + 10: "StraTracker not locked so trigger porbably bogus.\n", + 11: "It is probably not a GRB or Transient(very low image significance; < 6.5).", + 12: "It is the catalog of sources to be blocked.\n", + 13: "There is a bright star nearby.\n", + 14: "This was orginally a SubTresh, but it is now converted to a real BAT_POS.\n", + 15: "This is a source that has purposefully been removed from on-board catalog.\n", + 16: "This matched a Nearby_Galaxy in the on-board catalog.\n", + 28: "There was a temporal coincidence with another event.\n", + 29: "There was a spatial coincidence with another event.\n", + 30: "This is a test submission", + } + comments = "".join( + [ + val + for (key, val) in flag_descriptions.items() + if (soln_status_bits[key] == 1) + ] + ) + + energy_ranges = [[15, 25], [15, 50], [25, 100], [50, 350]] + energy_range_idx = np.flip(bin[37:38].view(dtype="i1"))[0] + energy_range = energy_ranges[energy_range_idx] + return { + "mission": "SWIFT", + "instrument": "BAT", + "id": [bin[4]], "trigger_time": utils.datetime_to_iso8601(bin[5], bin[6]), + "trigger_type": "image" if soln_status_bits[4] == 1 else "rate", + "image_duration": integ_time if soln_status_bits[4] == 1 else None, + "image_energy_range": energy_range if soln_status_bits[4] == 1 else None, + "rate_duration": integ_time if soln_status_bits[4] == 0 else None, + "rate_energy_range": integ_time if soln_status_bits[4] == 0 else None, "ra": 1e-4 * bin[7], "dec": 1e-4 * bin[8], "ra_dec_error": 1e-4 * bin[11], + "instrument_phi": 1e-2 * bin[12], + "instrument_theta": 1e-2 * bin[13], + "latitude": lat * 1e-2, + "longitude": lon * 1e-2, + "rate_snr": bin[21] * 1e-2, + "image_snr": bin[20] * 1e-2, + "n_events": bin[9], + "image_peak": bin[10], + "background_events": bin[22], + "background_start_time": utils.datetime_to_iso8601(bin[5], bin[23]), + "backgroun_duration": bin[24] * 1e-2, + "trigger_index": bin[17], + "catalog_number": bin[25] if soln_status_bits[3] == 1 else None, + "additional_info": comments if comments else None, } diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json index d493ebb..b966c93 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json @@ -1,6 +1,30 @@ { + "mission": "SWIFT", + "instrument": "BAT", + "id": [ + 1227767 + ], "trigger_time": "2024-05-11T18:06:53.220Z", + "trigger_type": "rate", + "image_duration": null, + "image_energy_range": null, + "rate_duration": 8.192, + "rate_energy_range": 8.192, "ra": 336.66450000000003, "dec": 8.5135, - "ra_dec_error": 0.05 + "ra_dec_error": 0.05, + "instrument_phi": -173.54, + "instrument_theta": 28.38, + "latitude": -11.14, + "longitude": 151.31, + "rate_snr": 14.89, + "image_snr": 8.52, + "n_events": 7538, + "image_peak": 281, + "background_events": 74677, + "background_start_time": "2024-05-11T18:06:22.570Z", + "backgroun_duration": 24.0, + "trigger_index": 262, + "catalog_number": null, + "additional_info": "A point source was found.\nIt is a GRB.\nThere was a spatial coincidence with another event.\n" } From fa2b436a78e0bd2defc5422105eae79a3e498f50 Mon Sep 17 00:00:00 2001 From: Athish Thiruvengadam Date: Thu, 8 Aug 2024 15:58:42 -0400 Subject: [PATCH 07/10] removed xfail test, moved dict outside of function and removed unncessary equalities changed Unused to intentionally omitted reformated comments --- .../notices/SWIFT_BAT_GRB_POS_ACK/__init__.py | 67 +++++++++---------- .../SWIFT_BAT_GRB_POS_ACK/example.json | 2 +- gcn_classic_to_json/test/test_notices.py | 11 +-- 3 files changed, 35 insertions(+), 45 deletions(-) diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py index a5d2c3a..9d28c60 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py @@ -2,13 +2,35 @@ from ... import utils +flag_descriptions = { + 0: "A point source was found.", + 1: "It is a GRB.", + 2: "It is an interesting src.", + 3: "It is in the flight catalog.", + 5: "It is definitely not a GRB.", + 6: "It is probably not a GRB or Transient(hi bkg level).", + 7: "It is probably not a GRB or Transient(low image significance; < 7).", + 8: "It is in the ground catalog.", + 9: "It is probably not a GRB or Transient(negative bkg slop).", + 10: "StraTracker not locked so trigger porbably bogus.", + 11: "It is probably not a GRB or Transient(very low image significance; < 6.5).", + 12: "It is the catalog of sources to be blocked.", + 13: "There is a bright star nearby.", + 14: "This was orginally a SubTresh, but it is now converted to a real BAT_POS.", + 15: "This is a source that has purposefully been removed from on-board catalog.", + 16: "This matched a Nearby_Galaxy in the on-board catalog.", + 28: "There was a temporal coincidence with another event.", + 29: "There was a spatial coincidence with another event.", + 30: "This is a test submission", +} + def parse(bin): bin[15] # Unused. According to docs: '4 bytes for the future' bin[19] # Unused. Flags are either internal or equivalent to bin[18] bin[26:36] # Unused. According to docs: '40 bytes for the future' bin[36] # Unused. Flags Equivalent to bin[18] - bin[38] # Unused. Sun/Moon parameters + bin[38] # Intentionally omitted. Sun/Moon parameters integ_time = bin[14] * 16 / 1000 @@ -16,35 +38,12 @@ def parse(bin): soln_status_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) - flag_descriptions = { - 0: "A point source was found.\n", - 1: "It is a GRB.\n", - 2: "It is an interesting src.\n", - 3: "It is in the flight catalog.\n", - 5: "It is definitely not a GRB.\n", - 6: "It is probably not a GRB or Transient(hi bkg level).\n", - 7: "It is probably not a GRB or Transient(low image significance; < 7).\n", - 8: "It is in the ground catalog.\n", - 9: "It is probably not a GRB or Transient(negative bkg slop).\n", - 10: "StraTracker not locked so trigger porbably bogus.\n", - 11: "It is probably not a GRB or Transient(very low image significance; < 6.5).", - 12: "It is the catalog of sources to be blocked.\n", - 13: "There is a bright star nearby.\n", - 14: "This was orginally a SubTresh, but it is now converted to a real BAT_POS.\n", - 15: "This is a source that has purposefully been removed from on-board catalog.\n", - 16: "This matched a Nearby_Galaxy in the on-board catalog.\n", - 28: "There was a temporal coincidence with another event.\n", - 29: "There was a spatial coincidence with another event.\n", - 30: "This is a test submission", - } - comments = "".join( - [ - val - for (key, val) in flag_descriptions.items() - if (soln_status_bits[key] == 1) - ] + comments = "\n".join( + [val for (key, val) in flag_descriptions.items() if (soln_status_bits[key])] ) + calalog_num = bin[25] + energy_ranges = [[15, 25], [15, 50], [25, 100], [50, 350]] energy_range_idx = np.flip(bin[37:38].view(dtype="i1"))[0] energy_range = energy_ranges[energy_range_idx] @@ -54,11 +53,11 @@ def parse(bin): "instrument": "BAT", "id": [bin[4]], "trigger_time": utils.datetime_to_iso8601(bin[5], bin[6]), - "trigger_type": "image" if soln_status_bits[4] == 1 else "rate", - "image_duration": integ_time if soln_status_bits[4] == 1 else None, - "image_energy_range": energy_range if soln_status_bits[4] == 1 else None, - "rate_duration": integ_time if soln_status_bits[4] == 0 else None, - "rate_energy_range": integ_time if soln_status_bits[4] == 0 else None, + "trigger_type": "image" if soln_status_bits[4] else "rate", + "image_duration": integ_time if soln_status_bits[4] else None, + "image_energy_range": energy_range if soln_status_bits[4] else None, + "rate_duration": integ_time if not soln_status_bits[4] else None, + "rate_energy_range": integ_time if not soln_status_bits[4] else None, "ra": 1e-4 * bin[7], "dec": 1e-4 * bin[8], "ra_dec_error": 1e-4 * bin[11], @@ -74,6 +73,6 @@ def parse(bin): "background_start_time": utils.datetime_to_iso8601(bin[5], bin[23]), "backgroun_duration": bin[24] * 1e-2, "trigger_index": bin[17], - "catalog_number": bin[25] if soln_status_bits[3] == 1 else None, + "catalog_number": calalog_num if soln_status_bits[3] else None, "additional_info": comments if comments else None, } diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json index b966c93..8d66a2a 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json @@ -26,5 +26,5 @@ "backgroun_duration": 24.0, "trigger_index": 262, "catalog_number": null, - "additional_info": "A point source was found.\nIt is a GRB.\nThere was a spatial coincidence with another event.\n" + "additional_info": "A point source was found.\nIt is a GRB.\nThere was a spatial coincidence with another event." } diff --git a/gcn_classic_to_json/test/test_notices.py b/gcn_classic_to_json/test/test_notices.py index c8fa286..864bb0d 100644 --- a/gcn_classic_to_json/test/test_notices.py +++ b/gcn_classic_to_json/test/test_notices.py @@ -11,12 +11,6 @@ files = importlib.resources.files(notices) -def keys_passing_except_for(*failing): - return list(set(notices.keys) - set(failing)) + [ - pytest.param(item, marks=pytest.mark.xfail) for item in failing - ] - - class NDArrayNanny(np.ndarray): """A ndarray subclass that tracks which elements have been accessed. @@ -44,10 +38,7 @@ def __getitem__(self, i): return super().__getitem__(i) -@pytest.mark.parametrize( - "key", - keys_passing_except_for("SWIFT_BAT_GRB_POS_ACK"), -) +@pytest.mark.parametrize("key", notices.keys) def test_all_fields_used(key, monkeypatch): """Check that every field in the binary packet is used in the conversion.""" From 81fb37913e72b3e9e0bab08894921d8698668c85 Mon Sep 17 00:00:00 2001 From: Athish Thiruvengadam Date: Tue, 13 Aug 2024 13:35:10 -0400 Subject: [PATCH 08/10] lifted energy range --- gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py index 9d28c60..f34cccb 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py @@ -24,6 +24,8 @@ 30: "This is a test submission", } +energy_ranges = [[15, 25], [15, 50], [25, 100], [50, 350]] + def parse(bin): bin[15] # Unused. According to docs: '4 bytes for the future' @@ -44,7 +46,6 @@ def parse(bin): calalog_num = bin[25] - energy_ranges = [[15, 25], [15, 50], [25, 100], [50, 350]] energy_range_idx = np.flip(bin[37:38].view(dtype="i1"))[0] energy_range = energy_ranges[energy_range_idx] From 8c6e5e23391372722bda29d26a16e16077860e3d Mon Sep 17 00:00:00 2001 From: Athish Thiruvengadam Date: Mon, 9 Sep 2024 15:45:41 -0500 Subject: [PATCH 09/10] coverted comments into fields f#inished comments --- .../notices/SWIFT_BAT_GRB_POS_ACK/__init__.py | 64 +++++++++++-------- .../SWIFT_BAT_GRB_POS_ACK/example.json | 13 +++- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py index f34cccb..37dcf85 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py @@ -2,29 +2,8 @@ from ... import utils -flag_descriptions = { - 0: "A point source was found.", - 1: "It is a GRB.", - 2: "It is an interesting src.", - 3: "It is in the flight catalog.", - 5: "It is definitely not a GRB.", - 6: "It is probably not a GRB or Transient(hi bkg level).", - 7: "It is probably not a GRB or Transient(low image significance; < 7).", - 8: "It is in the ground catalog.", - 9: "It is probably not a GRB or Transient(negative bkg slop).", - 10: "StraTracker not locked so trigger porbably bogus.", - 11: "It is probably not a GRB or Transient(very low image significance; < 6.5).", - 12: "It is the catalog of sources to be blocked.", - 13: "There is a bright star nearby.", - 14: "This was orginally a SubTresh, but it is now converted to a real BAT_POS.", - 15: "This is a source that has purposefully been removed from on-board catalog.", - 16: "This matched a Nearby_Galaxy in the on-board catalog.", - 28: "There was a temporal coincidence with another event.", - 29: "There was a spatial coincidence with another event.", - 30: "This is a test submission", -} - energy_ranges = [[15, 25], [15, 50], [25, 100], [50, 350]] +start_tracker_status = ["locked", "not locked"] def parse(bin): @@ -39,10 +18,30 @@ def parse(bin): lat, lon = bin[16:17].view(">i2") soln_status_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) - - comments = "\n".join( - [val for (key, val) in flag_descriptions.items() if (soln_status_bits[key])] - ) + soln_status_bits[8] # Unused. According to docs: 'ground_catalog_source'. + soln_status_bits[12] # Unused. According to docs: 'blocked_catalog_source'. + # These seems to be cross-referenced with a ground catalog with the name of the source printed in the text notices. + # But since the name of this source isn't stored in the these packets, I don't see a reason to include it. + if soln_status_bits[11]: + grb_status = ( + "It is probably not a GRB or transient due to very low image significance" + ) + elif soln_status_bits[7]: + grb_status = ( + "It is probably not a GRB or transient due to low image significance" + ) + elif soln_status_bits[9]: + grb_status = ( + "It is probably not a GRB or transient due to negative background slope" + ) + elif soln_status_bits[6]: + grb_status = ( + "It is probably not a GRB or transient due to high background level" + ) + elif soln_status_bits[1]: + grb_status = "It is a GRB" + else: + grb_status = "It is not a GRB" calalog_num = bin[25] @@ -53,6 +52,8 @@ def parse(bin): "mission": "SWIFT", "instrument": "BAT", "id": [bin[4]], + "alert_tense": "test" if soln_status_bits[30] else "current", + "alert_type": "retraction" if soln_status_bits[5] else "initial", "trigger_time": utils.datetime_to_iso8601(bin[5], bin[6]), "trigger_type": "image" if soln_status_bits[4] else "rate", "image_duration": integ_time if soln_status_bits[4] else None, @@ -75,5 +76,14 @@ def parse(bin): "backgroun_duration": bin[24] * 1e-2, "trigger_index": bin[17], "catalog_number": calalog_num if soln_status_bits[3] else None, - "additional_info": comments if comments else None, + "grb_status": grb_status, + "point_source": bool(soln_status_bits[0]), + "flaring_known_source": bool(soln_status_bits[2]), + "star_tracker_status": start_tracker_status[soln_status_bits[10]], + "bright_star_nearby": bool(soln_status_bits[13]), + "originally_subtresh": bool(soln_status_bits[14]), + "removed_from_catalog": bool(soln_status_bits[15]), + "galaxy_nearby": bool(soln_status_bits[16]), + "temporal_coincidence": bool(soln_status_bits[28]), + "spatial_coincidence": bool(soln_status_bits[29]), } diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json index 8d66a2a..0d33ae8 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json @@ -4,6 +4,8 @@ "id": [ 1227767 ], + "alert_tense": "current", + "alert_type": "initial", "trigger_time": "2024-05-11T18:06:53.220Z", "trigger_type": "rate", "image_duration": null, @@ -26,5 +28,14 @@ "backgroun_duration": 24.0, "trigger_index": 262, "catalog_number": null, - "additional_info": "A point source was found.\nIt is a GRB.\nThere was a spatial coincidence with another event." + "grb_status": "It is a GRB", + "point_source": true, + "flaring_known_source": false, + "star_tracker_status": "locked", + "bright_star_nearby": false, + "originally_subtresh": false, + "removed_from_catalog": false, + "galaxy_nearby": false, + "temporal_coincidence": false, + "spatial_coincidence": true } From 9a3c48f9b9cac534a3f9e7aee48cad49b1475768 Mon Sep 17 00:00:00 2001 From: Athish Thiruvengadam Date: Sun, 15 Sep 2024 23:55:15 -0500 Subject: [PATCH 10/10] Added all other SWIFT_BAT notices --- .../notices/SWIFT_BAT_GRB_LC/__init__.py | 62 ++++++++++++++ .../notices/SWIFT_BAT_GRB_LC/example.json | 29 +++++++ .../notices/SWIFT_BAT_GRB_POS_ACK/__init__.py | 27 ++++--- .../SWIFT_BAT_GRB_POS_ACK/example.json | 19 +++-- .../SWIFT_BAT_GRB_POS_TEST/__init__.py | 44 ++++++++++ .../SWIFT_BAT_GRB_POS_TEST/example.json | 28 +++++++ .../notices/SWIFT_BAT_QL_POS/__init__.py | 34 ++++++++ .../notices/SWIFT_BAT_QL_POS/example.json | 18 +++++ .../notices/SWIFT_BAT_SCALEDMAP/__init__.py | 61 ++++++++++++++ .../notices/SWIFT_BAT_SCALEDMAP/example.json | 26 ++++++ .../notices/SWIFT_BAT_TRANS/__init__.py | 81 +++++++++++++++++++ .../notices/SWIFT_BAT_TRANS/example.json | 39 +++++++++ 12 files changed, 450 insertions(+), 18 deletions(-) create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_GRB_LC/__init__.py create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_GRB_LC/example.json create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_TEST/__init__.py create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_TEST/example.json create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_QL_POS/__init__.py create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_QL_POS/example.json create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_SCALEDMAP/__init__.py create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_SCALEDMAP/example.json create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_TRANS/__init__.py create mode 100644 gcn_classic_to_json/notices/SWIFT_BAT_TRANS/example.json diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_LC/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_LC/__init__.py new file mode 100644 index 0000000..44cc8b7 --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_LC/__init__.py @@ -0,0 +1,62 @@ +import numpy as np + +from ... import utils +from ..SWIFT_BAT_GRB_POS_ACK import parse_swift_bat + +start_tracker_status = ["locked", "not locked"] + + +def parse(bin): + bin[9:12] # Unused. According to docs: '12 bytes for the future' + bin[19] # Unused. Flags are either internal or equivalent to bin[18] + + soln_status_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) + + if soln_status_bits[11]: + grb_status = ( + "It is probably not a GRB or transient due to very low image significance" + ) + elif soln_status_bits[7]: + grb_status = ( + "It is probably not a GRB or transient due to low image significance" + ) + elif soln_status_bits[9]: + grb_status = ( + "It is probably not a GRB or transient due to negative background slope" + ) + elif soln_status_bits[6]: + grb_status = ( + "It is probably not a GRB or transient due to high background level" + ) + elif soln_status_bits[1]: + grb_status = "It is a GRB" + else: + grb_status = "It is not a GRB" + + integ_time = bin[15] * 4 / 1000 + + lat, lon = bin[16:17].view(">i2") + + return { + **parse_swift_bat(bin), + "latitude": lat * 1e-2, + "longitude": lon * 1e-2, + "trigger_type": "image" if soln_status_bits[4] else "rate", + "rate_duration": integ_time if not soln_status_bits[4] else None, + "rate_energy_range": integ_time if not soln_status_bits[4] else None, + "instrument_phi": 1e-2 * bin[12], + "instrument_theta": 1e-2 * bin[13], + "rate_snr": bin[21] * 1e-2, + "image_snr": bin[20] * 1e-2, + "delta_time": bin[14] * 1e-2, + "trigger_index": bin[17], + "url": "http://gcn.gsfc.nasa.gov/gcn/notices_s/" + + utils.binary_to_string(bin[22:39]), + "grb_status": grb_status, + "point_source": bool(soln_status_bits[0]), + "flaring_known_source": bool(soln_status_bits[2]), + "star_tracker_status": start_tracker_status[soln_status_bits[10]], + "bright_star_nearby": bool(soln_status_bits[13]), + "removed_from_catalog": bool(soln_status_bits[15]), + "galaxy_nearby": bool(soln_status_bits[16]), + } diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_LC/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_LC/example.json new file mode 100644 index 0000000..70335c6 --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_LC/example.json @@ -0,0 +1,29 @@ +{ + "mission": "SWIFT", + "instrument": "BAT", + "id": [ + 1227767 + ], + "trigger_time": "2024-05-11T18:06:53.220Z", + "ra": 336.66450000000003, + "dec": 8.5135, + "rate_snr": 14.89, + "latitude": -11.14, + "longitude": 151.31, + "trigger_type": "rate", + "rate_duration": 2.048, + "rate_energy_range": 2.048, + "instrument_phi": -173.54, + "instrument_theta": 28.38, + "image_snr": 8.52, + "delta_time": -24.0, + "trigger_index": 262, + "url": "http://gcn.gsfc.nasa.gov/gcn/notices_s/sw01227767000msb.lc", + "grb_status": "It is a GRB", + "point_source": true, + "flaring_known_source": false, + "star_tracker_status": "locked", + "bright_star_nearby": false, + "removed_from_catalog": false, + "galaxy_nearby": false +} diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py index 37dcf85..8a5ebe5 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/__init__.py @@ -6,6 +6,18 @@ start_tracker_status = ["locked", "not locked"] +def parse_swift_bat(bin): + return { + "mission": "SWIFT", + "instrument": "BAT", + "id": [bin[4]], + "trigger_time": utils.datetime_to_iso8601(bin[5], bin[6]), + "ra": 1e-4 * bin[7], + "dec": 1e-4 * bin[8], + "rate_snr": bin[21] * 1e-2, + } + + def parse(bin): bin[15] # Unused. According to docs: '4 bytes for the future' bin[19] # Unused. Flags are either internal or equivalent to bin[18] @@ -13,7 +25,7 @@ def parse(bin): bin[36] # Unused. Flags Equivalent to bin[18] bin[38] # Intentionally omitted. Sun/Moon parameters - integ_time = bin[14] * 16 / 1000 + integ_time = bin[14] * 4 / 1000 lat, lon = bin[16:17].view(">i2") @@ -49,24 +61,19 @@ def parse(bin): energy_range = energy_ranges[energy_range_idx] return { - "mission": "SWIFT", - "instrument": "BAT", - "id": [bin[4]], + **parse_swift_bat(bin), "alert_tense": "test" if soln_status_bits[30] else "current", "alert_type": "retraction" if soln_status_bits[5] else "initial", - "trigger_time": utils.datetime_to_iso8601(bin[5], bin[6]), + "latitude": lat * 1e-2, + "longitude": lon * 1e-2, "trigger_type": "image" if soln_status_bits[4] else "rate", "image_duration": integ_time if soln_status_bits[4] else None, "image_energy_range": energy_range if soln_status_bits[4] else None, "rate_duration": integ_time if not soln_status_bits[4] else None, - "rate_energy_range": integ_time if not soln_status_bits[4] else None, - "ra": 1e-4 * bin[7], - "dec": 1e-4 * bin[8], + "rate_energy_range": energy_range if not soln_status_bits[4] else None, "ra_dec_error": 1e-4 * bin[11], "instrument_phi": 1e-2 * bin[12], "instrument_theta": 1e-2 * bin[13], - "latitude": lat * 1e-2, - "longitude": lon * 1e-2, "rate_snr": bin[21] * 1e-2, "image_snr": bin[20] * 1e-2, "n_events": bin[9], diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json index 0d33ae8..32cb6ec 100644 --- a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_ACK/example.json @@ -4,22 +4,25 @@ "id": [ 1227767 ], + "trigger_time": "2024-05-11T18:06:53.220Z", + "ra": 336.66450000000003, + "dec": 8.5135, + "rate_snr": 14.89, "alert_tense": "current", "alert_type": "initial", - "trigger_time": "2024-05-11T18:06:53.220Z", + "latitude": -11.14, + "longitude": 151.31, "trigger_type": "rate", "image_duration": null, "image_energy_range": null, - "rate_duration": 8.192, - "rate_energy_range": 8.192, - "ra": 336.66450000000003, - "dec": 8.5135, + "rate_duration": 2.048, + "rate_energy_range": [ + 25, + 100 + ], "ra_dec_error": 0.05, "instrument_phi": -173.54, "instrument_theta": 28.38, - "latitude": -11.14, - "longitude": 151.31, - "rate_snr": 14.89, "image_snr": 8.52, "n_events": 7538, "image_peak": 281, diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_TEST/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_TEST/__init__.py new file mode 100644 index 0000000..87bc64d --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_TEST/__init__.py @@ -0,0 +1,44 @@ +import numpy as np + +from ... import utils +from ..SWIFT_BAT_GRB_POS_ACK import parse_swift_bat + +grb_status = ["It is not a GRB", "It is a GRB"] + + +def parse(bin): + bin[15] # Unused. According to docs: '4 bytes for the future' + bin[16] # Unused. According to docs: 'always be 0.00,0.00 for this notice' + bin[19] # Unused. Flags are either internal or equivalent to bin[18] + bin[25:36] # Unused. According to docs: '44 bytes for the future' + bin[36:38] # Intentionally Omitted. Flags are redundant with rest of notice + bin[38] # Intentionally omitted. Sun/Moon parameters + + integ_time = bin[14] * 4 / 1000 + + soln_status_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) + soln_status_bits[8] # Unused. According to docs: 'ground_catalog_source'. + soln_status_bits[12] # Unused. According to docs: 'blocked_catalog_source'. + # These seems to be cross-referenced with a ground catalog with the name of the source printed in the text notices. + # But since the name of this source isn't stored in the these packets, I don't see a reason to include it. + + return { + **parse_swift_bat(bin), + "alert_tense": "test", + "ra_dec_error": 1e-4 * bin[11], + "instrument_phi": 1e-2 * bin[12], + "instrument_theta": 1e-2 * bin[13], + "image_duration": integ_time if soln_status_bits[4] else None, + "rate_duration": integ_time if not soln_status_bits[4] else None, + "image_snr": bin[20] * 1e-2, + "n_events": bin[9], + "image_peak": bin[10], + "background_events": bin[22], + "background_start_time": utils.datetime_to_iso8601(bin[5], bin[23]), + "backgroun_duration": bin[24] * 1e-2, + "trigger_index": bin[17], + "grb_status": grb_status[soln_status_bits[1]], + "point_source": bool(soln_status_bits[0]), + "flaring_known_source": bool(soln_status_bits[2]), + "bright_star_nearby": bool(soln_status_bits[13]), + } diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_TEST/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_TEST/example.json new file mode 100644 index 0000000..1361daa --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_GRB_POS_TEST/example.json @@ -0,0 +1,28 @@ +{ + "mission": "SWIFT", + "instrument": "BAT", + "id": [ + 99999 + ], + "trigger_time": "2024-05-12T07:26:09.000Z", + "ra": 180.0, + "dec": -35.0, + "rate_snr": 16.78, + "alert_tense": "test", + "ra_dec_error": 0.05, + "instrument_phi": 123.54, + "instrument_theta": 12.34, + "image_duration": null, + "rate_duration": 0.064, + "image_snr": 12.98, + "n_events": 1000, + "image_peak": 500, + "background_events": 100, + "background_start_time": "2024-05-12T07:25:42.000Z", + "backgroun_duration": 12.0, + "trigger_index": 12, + "grb_status": "It is a GRB", + "point_source": true, + "flaring_known_source": false, + "bright_star_nearby": false +} diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_QL_POS/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_QL_POS/__init__.py new file mode 100644 index 0000000..5a25040 --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_QL_POS/__init__.py @@ -0,0 +1,34 @@ +import numpy as np + +from ..SWIFT_BAT_GRB_POS_ACK import parse_swift_bat + + +def parse(bin): + bin[12:17] # Unused. According to docs: '20 bytes for the future' + bin[19] # Intentionally Omitted. According to docs: 'miscellaneous bits' + bin[20] # Unused. According to docs: '4 bytes for the future' + bin[22:38] # Unused. According to docs: '64 bytes for the future' + + lat, lon = bin[10:11].view(">i2") + + at_slew_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) + + at_slew_flag_descriptions = { + 0: "This burst is worthy of becoming the new Automated target.", + 1: "This burst is of sufficient merit to request a s/c slew.", + } + + comments = "".join( + [val for (key, val) in at_slew_flag_descriptions.items() if (at_slew_bits[key])] + ) + + return { + **parse_swift_bat(bin), + "latitude": lat * 1e-2, + "longitude": lon * 1e-2, + "ra_dec_error": 1e-4 * bin[11], + "roll": bin[9] * 1e-4, + "trigger_index": bin[17], + "merit_value": bin[38] * 1e-2, + "additional_info": comments if comments else None, + } diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_QL_POS/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_QL_POS/example.json new file mode 100644 index 0000000..e2b1557 --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_QL_POS/example.json @@ -0,0 +1,18 @@ +{ + "mission": "SWIFT", + "instrument": "BAT", + "id": [ + 1227767 + ], + "trigger_time": "2024-05-11T18:06:53.340Z", + "ra": 336.66450000000003, + "dec": 8.5135, + "rate_snr": 14.89, + "latitude": -11.14, + "longitude": 151.31, + "ra_dec_error": 0.05, + "roll": 0.0, + "trigger_index": 262, + "merit_value": 100.0, + "additional_info": "This burst is worthy of becoming the new Automated target.This burst is of sufficient merit to request a s/c slew." +} diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_SCALEDMAP/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_SCALEDMAP/__init__.py new file mode 100644 index 0000000..6f9b75a --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_SCALEDMAP/__init__.py @@ -0,0 +1,61 @@ +import numpy as np + +from ... import utils +from ..SWIFT_BAT_GRB_POS_ACK import parse_swift_bat + +start_tracker_status = ["locked", "not locked"] + + +def parse(bin): + bin[9:14] # Unused. According to docs: '20 bytes for the future' + bin[ + 17 + ] # Unused. According to docs: 'trig_index. This field is not yet (if ever) assigned.' + bin[19] # Unused. Flags are either internal or equivalent to bin[18] + + integ_time = bin[15] * 4 / 1000 # misc_bit has to be defined + + lat, lon = bin[16:17].view(">i2") + + soln_status_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) + + if soln_status_bits[11]: + grb_status = ( + "It is probably not a GRB or transient due to very low image significance" + ) + elif soln_status_bits[7]: + grb_status = ( + "It is probably not a GRB or transient due to low image significance" + ) + elif soln_status_bits[9]: + grb_status = ( + "It is probably not a GRB or transient due to negative background slope" + ) + elif soln_status_bits[6]: + grb_status = ( + "It is probably not a GRB or transient due to high background level" + ) + elif soln_status_bits[1]: + grb_status = "It is a GRB" + else: + grb_status = "It is not a GRB" + + return { + **parse_swift_bat(bin), + "alert_type": "retraction" if soln_status_bits[5] else "initial", + "latitude": lat * 1e-2, + "longitude": lon * 1e-2, + "foreground_duration": bin[14] * 1e-3, + "image_duration": integ_time if soln_status_bits[4] else None, + "rate_duration": integ_time if not soln_status_bits[4] else None, + "image_snr": bin[20] * 1e-2, + "grb_status": grb_status, + "point_source": bool(soln_status_bits[0]), + "flaring_known_source": bool(soln_status_bits[2]), + "star_tracker_status": start_tracker_status[soln_status_bits[10]], + "bright_star_nearby": bool(soln_status_bits[13]), + "originally_subtresh": bool(soln_status_bits[14]), + "removed_from_catalog": bool(soln_status_bits[15]), + "url": "http://gcn.gsfc.nasa.gov/gcn/notices_s/" + + utils.binary_to_string(bin[22:39]), + } diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_SCALEDMAP/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_SCALEDMAP/example.json new file mode 100644 index 0000000..5e3bfb3 --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_SCALEDMAP/example.json @@ -0,0 +1,26 @@ +{ + "mission": "SWIFT", + "instrument": "BAT", + "id": [ + 1230423 + ], + "trigger_time": "2024-05-23T14:43:11.900Z", + "ra": 10.916400000000001, + "dec": 14.3419, + "rate_snr": 8.540000000000001, + "alert_type": "initial", + "latitude": 8.9, + "longitude": 279.27, + "foreground_duration": 4.095, + "image_duration": null, + "rate_duration": 4.096, + "image_snr": 8.5, + "grb_status": "It is a GRB", + "point_source": true, + "flaring_known_source": false, + "star_tracker_status": "locked", + "bright_star_nearby": false, + "originally_subtresh": false, + "removed_from_catalog": false, + "url": "http://gcn.gsfc.nasa.gov/gcn/notices_s/sw01230423000msbsm.fits" +} diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_TRANS/__init__.py b/gcn_classic_to_json/notices/SWIFT_BAT_TRANS/__init__.py new file mode 100644 index 0000000..a609821 --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_TRANS/__init__.py @@ -0,0 +1,81 @@ +import numpy as np + +from ... import utils +from ..SWIFT_BAT_GRB_POS_ACK import parse_swift_bat + +energy_ranges = [[15, 25], [15, 50], [25, 100], [50, 350]] +start_tracker_status = ["locked", "not locked"] + + +def parse(bin): + bin[15] # Unused. According to docs: '4 bytes for the future' + bin[19] # Unused. Flags are either internal or equivalent to bin[18] + bin[26:36] # Unused. According to docs: '40 bytes for the future' + bin[36] # Unused. Flags Equivalent to bin[18] + bin[38] # Intentionally omitted. Sun/Moon parameters + + integ_time = bin[14] * 4 / 1000 + + lat, lon = bin[16:17].view(">i2") + + soln_status_bits = np.flip(np.unpackbits(bin[18:19].view(dtype="u1"))) + + soln_status_bits[8] # Unused. According to docs: 'ground_catalog_source'. + soln_status_bits[12] # Unused. According to docs: 'blocked_catalog_source'. + # These seems to be cross-referenced with a ground catalog with the name of the source printed in the text notices. + # But since the name of this source isn't stored in the these packets, I don't see a reason to include it. + if soln_status_bits[11]: + grb_status = ( + "It is probably not a GRB or transient due to very low image significance" + ) + elif soln_status_bits[7]: + grb_status = ( + "It is probably not a GRB or transient due to low image significance" + ) + elif soln_status_bits[9]: + grb_status = ( + "It is probably not a GRB or transient due to negative background slope" + ) + elif soln_status_bits[6]: + grb_status = ( + "It is probably not a GRB or transient due to high background level" + ) + elif soln_status_bits[1]: + grb_status = "It is a GRB" + else: + grb_status = "It is not a GRB" + + calalog_num = bin[25] + + energy_range_idx = np.flip(bin[37:38].view(dtype="i1"))[0] + energy_range = energy_ranges[energy_range_idx] + + return { + **parse_swift_bat(bin), + "ra_dec_error": bin[11] * 1e-4, + "instrument_phi": bin[12] * 1e-4, + "instrument_theta": bin[13] * 1e-4, + "latitude": lat * 1e-2, + "longitude": lon * 1e-2, + "trigger_type": "image" if soln_status_bits[4] else "rate", + "image_duration": integ_time if soln_status_bits[4] else None, + "image_energy_range": energy_range if soln_status_bits[4] else None, + "rate_duration": integ_time if not soln_status_bits[4] else None, + "rate_energy_range": energy_range if not soln_status_bits[4] else None, + "rate_snr": bin[21] * 1e-2, + "image_snr": bin[20] * 1e-2, + "n_events": bin[9], + "image_peak": bin[10], + "background_events": bin[22], + "background_start_time": utils.datetime_to_iso8601(bin[5], bin[23]), + "backgroun_duration": bin[24] * 1e-2, + "trigger_index": bin[17], + "catalog_number": calalog_num if soln_status_bits[3] else None, + "grb_status": grb_status, + "point_source": bool(soln_status_bits[0]), + "flaring_known_source": bool(soln_status_bits[2]), + "star_tracker_status": start_tracker_status[soln_status_bits[10]], + "bright_star_nearby": bool(soln_status_bits[13]), + "temporal_coincidence": bool(soln_status_bits[28]), + "spatial_coincidence": bool(soln_status_bits[29]), + } diff --git a/gcn_classic_to_json/notices/SWIFT_BAT_TRANS/example.json b/gcn_classic_to_json/notices/SWIFT_BAT_TRANS/example.json new file mode 100644 index 0000000..b694396 --- /dev/null +++ b/gcn_classic_to_json/notices/SWIFT_BAT_TRANS/example.json @@ -0,0 +1,39 @@ +{ + "mission": "SWIFT", + "instrument": "BAT", + "id": [ + 1236151 + ], + "trigger_time": "2024-06-10T07:36:36.410Z", + "ra": 117.1755, + "dec": -67.804, + "rate_snr": 7.54, + "ra_dec_error": 0.05, + "instrument_phi": 0.6051000000000001, + "instrument_theta": 0.1106, + "latitude": -11.02, + "longitude": 68.08, + "trigger_type": "rate", + "image_duration": null, + "image_energy_range": null, + "rate_duration": 2.048, + "rate_energy_range": [ + 15, + 25 + ], + "image_snr": 6.59, + "n_events": 2700, + "image_peak": 127, + "background_events": 26505, + "background_start_time": "2024-06-10T07:35:58.390Z", + "backgroun_duration": 24.0, + "trigger_index": 244, + "catalog_number": 10324, + "grb_status": "It is probably not a GRB or transient due to low image significance", + "point_source": true, + "flaring_known_source": true, + "star_tracker_status": "locked", + "bright_star_nearby": false, + "temporal_coincidence": false, + "spatial_coincidence": false +}