antares-devkit 0.4.0__py3-none-any.whl → 0.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,189 @@
1
+ ## v2
2
+ from antares_devkit.models import BaseFilter
3
+
4
+
5
+ class rubin_NovTest_soraisam(BaseFilter):
6
+ ## MS: this is mainly for the NOIRLab end-to-end demonstration
7
+
8
+ TRIGGERING_SURVEY = "lsst"
9
+
10
+ SLACK_CHANNEL = "#filter-rubin-novtest"
11
+
12
+ REQUIRED_LOCUS_PROPERTIES = []
13
+
14
+ ## bare absolute minimum alert properties proving it's good to go
15
+ REQUIRED_ALERT_PROPERTIES = [
16
+ "lsst_diaSource_reliability",
17
+ "lsst_diaSource_snr",
18
+ "lsst_diaSource_ssObjectId",
19
+ "lsst_diaSource_extendedness",
20
+ "lsst_diaSource_templateFlux",
21
+ "lsst_diaSource_templateFluxErr",
22
+ "lsst_diaSource_isNegative",
23
+ "ant_mjd",
24
+ "ant_mag",
25
+ "ant_passband",
26
+ ]
27
+
28
+
29
+ OUTPUT_LOCUS_TAGS = [
30
+ {
31
+ "name": "SN_candies",
32
+ "description": "Locus is a SN candidate in the Rubin alert stream.",
33
+ },
34
+ ]
35
+
36
+ # Slack post (going to tda-noao noirlab_e2e_demo channel)
37
+ def send_message_to_slack(self, msg):
38
+ from slack_sdk import WebClient
39
+ from slack_sdk.errors import SlackApiError
40
+ import os
41
+
42
+ slack_token = os.getenv("RUBIN_NOVTEST_SLACK_TOKEN", "")
43
+ channel_id = os.getenv("RUBIN_NOVTEST_SLACK_CHANNEL_ID", "")
44
+ if (not slack_token) or (not channel_id):
45
+ print ("Slack not set up")
46
+ return
47
+ client = WebClient(token=slack_token)
48
+
49
+ try:
50
+ response = client.chat_postMessage(
51
+ channel=channel_id,
52
+ text=msg
53
+ )
54
+ # print(f"Message sent successfully: {response['ts']}")
55
+ except SlackApiError as e:
56
+ print(f"Error sending message: {e.response['error']}")
57
+ pass
58
+
59
+ return
60
+
61
+
62
+
63
+
64
+ def _run(self, locus):
65
+ import numpy as np
66
+ from astropy.time import Time
67
+ from astropy.coordinates import SkyCoord
68
+ import astropy.units as U
69
+ from itertools import combinations
70
+ import os
71
+
72
+ antares_environment = os.getenv("ANTARES_ENVIRONMENT_URL", "")
73
+
74
+ C1 = (locus.alert.properties['lsst_diaSource_reliability'] < 0.9) or (locus.alert.properties['lsst_diaSource_snr'] < 10.0)
75
+ if C1:
76
+ return
77
+
78
+ C2 = (locus.alert.properties['lsst_diaSource_ssObjectId'] != 0)
79
+ if C2:
80
+ return
81
+
82
+ ## extract info from recent alert
83
+ alert_id = locus.alert.alert_id
84
+ current = Time(locus.alert.properties['ant_mjd'], format="mjd")
85
+ current_mag = locus.alert.properties['ant_mag']
86
+ current_pb = locus.alert.properties['ant_passband']
87
+
88
+ # ## confirm locus is Not in legacy point source catalogs
89
+ astro_objects = locus.catalog_objects
90
+ if astro_objects and "2mass_psc" in astro_objects.keys():
91
+ return
92
+
93
+
94
+
95
+ TS_all = locus.timeseries('all')
96
+ TS_lsst = locus.timeseries('lsst')
97
+
98
+ ## want more than two measurements across all filters and time span less than 15 days (young)
99
+ C4 = (len(TS_all) > 2) and (max(TS_lsst["ant_mjd"].data) - min(TS_lsst["ant_mjd"].data) < 15.0)
100
+ if not C4:
101
+ return
102
+
103
+ ## want star like profile
104
+ try:
105
+ C5 = np.ma.median(TS_lsst['lsst_diaSource_extendedness'].data) > 0.3
106
+ if C5:
107
+ return
108
+ except: ## some alerts do not have extendedness apparently
109
+ print ("extendedness not in alert packet")
110
+ return
111
+
112
+
113
+ C6 = np.ma.median(np.abs(TS_lsst['lsst_diaSource_templateFlux'].data/TS_lsst['lsst_diaSource_templateFluxErr'].data))<1000.0
114
+ if not C6:
115
+ return
116
+
117
+ C7 = np.all(TS_lsst['lsst_diaSource_isNegative'].data==False)
118
+ if not C7:
119
+ return
120
+
121
+
122
+ rubin_pb = ['u','g','r','i','z']
123
+ x = TS_lsst["ant_mjd"].data
124
+ y = TS_lsst["ant_mag"].data
125
+ pb = TS_lsst["ant_passband"].data
126
+
127
+
128
+ def is_it_blue_color(p1, p2):
129
+ g_x_i = x[pb == p1]
130
+ g_y_i = y[pb == p1]
131
+ R_x_i = x[pb == p2]
132
+ R_y_i = y[pb == p2]
133
+
134
+ idx = np.argsort(g_x_i)
135
+ g_x = g_x_i[idx]
136
+ g_y = g_y_i[idx]
137
+ idx = np.argsort(R_x_i)
138
+ R_x = R_x_i[idx]
139
+ R_y = R_y_i[idx]
140
+
141
+ dt = []
142
+ dc = []
143
+ for a, b in zip(g_x, g_y):
144
+ dt_i = np.abs(a - R_x)
145
+ dc_i = b - R_y
146
+ if min(dt_i) <= 1.0:
147
+ dt.append(min(dt_i))
148
+ dc.append(dc_i[np.argmin(dt_i)])
149
+
150
+
151
+ if len(dc) > 1:
152
+ col_evol = np.argsort(
153
+ dc
154
+ )
155
+ ori_idx = np.arange(len(dc))
156
+ idx_diff = col_evol[::-1] - ori_idx
157
+ if np.sum(idx_diff == 0) >= 0.5 * len(dc):
158
+ return True
159
+
160
+ return False
161
+
162
+ C8 = False
163
+ for p1, p2 in combinations(rubin_pb, 2):
164
+ if np.sum(pb == p1) > 1 and np.sum(pb == p2) > 0:
165
+ if is_it_blue_color(p1, p2):
166
+ C8 = True
167
+ break
168
+ if not C8:
169
+ return
170
+
171
+
172
+
173
+ ant_id = locus.locus_id
174
+
175
+ ## for slack notification whether known to TNS
176
+ if astro_objects and "tns_public_objects" in astro_objects.keys():
177
+ known_to_tns = "in TNS"
178
+ else:
179
+ known_to_tns = "NOT in TNS"
180
+
181
+ coord = SkyCoord(locus.ra, locus.dec, unit=(U.deg, U.deg))
182
+ ra_str = f"{int(coord.ra.hms.h):02d}:{int(coord.ra.hms.m):02d}:{coord.ra.hms.s:05.2f}"
183
+ dec_str = f"{int(coord.dec.dms.d):02d}:{abs(int(coord.dec.dms.m)):02d}:{abs(coord.dec.dms.s):05.2f}"
184
+
185
+ locus.tag("SN_candies")
186
+
187
+ msg = f"Young SN candidate: triggering alert={alert_id} for locus <{antares_environment}/loci/{ant_id}|{ant_id}> {known_to_tns}, RA={ra_str} DEC={dec_str}, {current_pb}_mag={current_mag:.2f}, #dets in LSST={len(TS_lsst)}, UTC={current.iso}"
188
+ if current_mag < 22.5:
189
+ self.send_message_to_slack(msg)
@@ -0,0 +1,147 @@
1
+ ## v1
2
+ from antares_devkit.models import BaseFilter
3
+
4
+
5
+ class young_rubin_transients_soraisam(BaseFilter):
6
+ ## MS: this is mainly for the NOIRLab end-to-end demonstration
7
+
8
+ TRIGGERING_SURVEY = "lsst"
9
+
10
+ SLACK_CHANNEL = "#filter-young-rubin-transients"
11
+
12
+ REQUIRED_LOCUS_PROPERTIES = []
13
+
14
+ ## bare absolute minimum alert properties proving it's good to go
15
+ REQUIRED_ALERT_PROPERTIES = [
16
+ "lsst_diaSource_reliability",
17
+ "lsst_diaSource_snr",
18
+ "lsst_diaSource_ssObjectId",
19
+ "lsst_diaSource_extendedness",
20
+ "lsst_diaSource_templateFlux",
21
+ "lsst_diaSource_templateFluxErr",
22
+ "lsst_diaSource_isNegative",
23
+ "ant_mjd",
24
+ "ant_mag",
25
+ "ant_passband",
26
+ ]
27
+
28
+
29
+ OUTPUT_LOCUS_TAGS = [
30
+ {
31
+ "name": "young_rubin_transients",
32
+ "description": "Locus is a young transient in the Rubin alert stream.",
33
+ },
34
+ ]
35
+
36
+ # Slack post (going to tda-noao noirlab_e2e_demo_2 channel)
37
+ def send_message_to_slack(self, msg):
38
+ from slack_sdk import WebClient
39
+ from slack_sdk.errors import SlackApiError
40
+ import os
41
+
42
+ slack_token = os.getenv("RUBIN_SORAISAM_SLACK_TOKEN", "")
43
+ channel_id = os.getenv("RUBIN_SORAISAM_SLACK_CHANNEL_ID", "")
44
+ if (not slack_token) or (not channel_id):
45
+ print ("Slack not set up")
46
+ return
47
+ client = WebClient(token=slack_token)
48
+
49
+ try:
50
+ response = client.chat_postMessage(
51
+ channel=channel_id,
52
+ text=msg
53
+ )
54
+ # print(f"Message sent successfully: {response['ts']}")
55
+ except SlackApiError as e:
56
+ print(f"Error sending message: {e.response['error']}")
57
+ pass
58
+
59
+ return
60
+
61
+
62
+
63
+
64
+ def _run(self, locus):
65
+ import numpy as np
66
+ from astropy.time import Time
67
+ from astropy.coordinates import SkyCoord
68
+ import astropy.units as U
69
+ from itertools import combinations
70
+ import os
71
+
72
+ antares_environment = os.getenv("ANTARES_ENVIRONMENT_URL", "")
73
+ C1 = (locus.alert.properties['lsst_diaSource_reliability'] < 0.9) or (locus.alert.properties['lsst_diaSource_snr'] < 10.0)
74
+ if C1:
75
+ return
76
+
77
+ C2 = (locus.alert.properties['lsst_diaSource_ssObjectId'] != 0)
78
+ if C2:
79
+ return
80
+
81
+ ## extract info from recent alert
82
+ alert_id = locus.alert.alert_id
83
+ current = Time(locus.alert.properties['ant_mjd'], format="mjd")
84
+ current_mag = locus.alert.properties['ant_mag']
85
+ current_pb = locus.alert.properties['ant_passband']
86
+
87
+ # ## confirm locus is extragalactic
88
+ astro_objects = locus.catalog_objects
89
+ # matching_catalog_names = astro_objects.keys()
90
+ # # Below is a battle-tested set of extended source catalogs (Antares-based names)
91
+ # xsc_cats = [
92
+ # "2mass_xsc",
93
+ # "ned",
94
+ # "nyu_valueadded_gals",
95
+ # "sdss_gals",
96
+ # "veron_agn_qso",
97
+ # "RC3",
98
+ # ]
99
+ # C3 = set(matching_catalog_names) & set(xsc_cats)
100
+ # if not C3:
101
+ # # print ("No match with extragalactic catalog")
102
+ # return
103
+
104
+
105
+
106
+ TS_all = locus.timeseries('all')
107
+ TS_lsst = locus.timeseries('lsst')
108
+
109
+ C4 = (len(TS_all) > 2) and (max(TS_lsst["ant_mjd"].data) - min(TS_lsst["ant_mjd"].data) < 15.0)
110
+ if not C4:
111
+ return
112
+
113
+ try:
114
+ C5 = np.ma.median(TS_lsst['lsst_diaSource_extendedness'].data) > 0.3
115
+ if C5:
116
+ return
117
+ except: ## some alerts do not have extendedness apparently
118
+ print ("extendedness not in alert packet")
119
+ return
120
+
121
+
122
+ C6 = np.ma.median(np.abs(TS_lsst['lsst_diaSource_templateFlux'].data/TS_lsst['lsst_diaSource_templateFluxErr'].data))<1000.0
123
+ if not C6:
124
+ return
125
+
126
+ C7 = np.all(TS_lsst['lsst_diaSource_isNegative'].data==False)
127
+ if not C7:
128
+ return
129
+
130
+
131
+ ant_id = locus.locus_id
132
+
133
+ ## for slack notification whether known to TNS
134
+ if astro_objects and "tns_public_objects" in astro_objects.keys():
135
+ known_to_tns = "in TNS"
136
+ else:
137
+ known_to_tns = "NOT in TNS"
138
+
139
+ coord = SkyCoord(locus.ra, locus.dec, unit=(U.deg, U.deg))
140
+ ra_str = f"{int(coord.ra.hms.h):02d}:{int(coord.ra.hms.m):02d}:{coord.ra.hms.s:05.2f}"
141
+ dec_str = f"{int(coord.dec.dms.d):02d}:{abs(int(coord.dec.dms.m)):02d}:{abs(coord.dec.dms.s):05.2f}"
142
+
143
+ locus.tag("young_rubin_transients")
144
+
145
+ msg = f"Young extragalactic transient: triggering alert={alert_id} for locus <{antares_environment}/loci/{ant_id}|{ant_id}> {known_to_tns}, RA={ra_str} DEC={dec_str}, {current_pb}_mag={current_mag:.2f}, #dets in LSST={len(TS_lsst)}, UTC={current.iso}"
146
+ if current_mag<22.5:
147
+ self.send_message_to_slack(msg)
antares_devkit/utils.py CHANGED
@@ -45,6 +45,8 @@ def get_filters_path():
45
45
  "TestDevZtf": "antares_devkit.filters.test_dev_ztf",
46
46
  "vpdf": "antares_devkit.filters.vpdf",
47
47
  "YoungExtragalacticCandidate": "antares_devkit.filters.young_extragalactic_candidate",
48
+ "rubin_NovTest_soraisam": "antares_devkit.filters.rubin_NovTest_soraisam",
49
+ "young_rubin_transients_soraisam": "antares_devkit.filters.young_rubin_transients_soraisam",
48
50
  }
49
51
 
50
52
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: antares-devkit
3
- Version: 0.4.0
3
+ Version: 0.5.1
4
4
  Summary: Provides tools and utility methods to write and debug ANTARES filters with Python.
5
5
  Keywords: antares,devkit,filter development
6
6
  Author-Email: NSF NOIRLab ANTARES Team <antares@noirlab.edu>
@@ -50,6 +50,7 @@ Requires-Dist: statsmodels>=0.12.2; extra == "filter-dependencies"
50
50
  Requires-Dist: scipy>=1.13.1; extra == "filter-dependencies"
51
51
  Requires-Dist: light-curve==0.7.2; extra == "filter-dependencies"
52
52
  Requires-Dist: ssi-forest>=0.1.1; extra == "filter-dependencies"
53
+ Requires-Dist: slack-sdk>=3.39.0; extra == "filter-dependencies"
53
54
  Provides-Extra: jupyter
54
55
  Requires-Dist: matplotlib>=3.9.4; extra == "jupyter"
55
56
  Description-Content-Type: text/markdown
@@ -1,7 +1,7 @@
1
- antares_devkit-0.4.0.dist-info/METADATA,sha256=ezUw4bjk-exbZyajpKsY1-DA2c57o4fYE43zzOl7FNk,6660
2
- antares_devkit-0.4.0.dist-info/WHEEL,sha256=tsUv_t7BDeJeRHaSrczbGeuK-TtDpGsWi_JfpzD255I,90
3
- antares_devkit-0.4.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
- antares_devkit-0.4.0.dist-info/licenses/LICENSE.txt,sha256=28klowHDSChBjMTdsDYYEguY0tSBl8-LCb1aFscRw_8,1522
1
+ antares_devkit-0.5.1.dist-info/METADATA,sha256=--zIngQGhiyEDnldN7wEuo0QgydHnR1SvOtJB_sN_fw,6725
2
+ antares_devkit-0.5.1.dist-info/WHEEL,sha256=Wb0ASbVj8JvWHpOiIpPi7ucfIgJeCi__PzivviEAQFc,90
3
+ antares_devkit-0.5.1.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
+ antares_devkit-0.5.1.dist-info/licenses/LICENSE.txt,sha256=28klowHDSChBjMTdsDYYEguY0tSBl8-LCb1aFscRw_8,1522
5
5
  antares_devkit/__init__.py,sha256=wkcoldBUr3l8I3p9q6RYyE1O0vMaWo7zS1_WYyxuHhA,80
6
6
  antares_devkit/filters/bad_detection/__init__.py,sha256=vJHaKZHVgjr2-xvGn2dfQxRnoEKIaUGH1JMSH9mCoHQ,768
7
7
  antares_devkit/filters/bad_seeing/__init__.py,sha256=aZeIoiLkaVe4OFVRW8tqdMF-lfDL3CKbt0nfjs3WJT0,687
@@ -33,6 +33,7 @@ antares_devkit/filters/persistent_dimmers/__init__.py,sha256=UGH9AtWpGSJpVR6JL6u
33
33
  antares_devkit/filters/random_tagger_filter/__init__.py,sha256=B2eJspxpwp3iRIMZ_vpD0_e8JWg5l_y7CPhdTAFYkIE,493
34
34
  antares_devkit/filters/recent_reddening/__init__.py,sha256=5fqthd_saqLLKmt-FB8_sufczuQ1IAsejo7Fhis_Lx8,3184
35
35
  antares_devkit/filters/refitt_newsources_snrcut/__init__.py,sha256=f1wz7lbSf5iGQVveBx-JEYjbGh0dzNVP-BYMcsSsh4Y,1536
36
+ antares_devkit/filters/rubin_NovTest_soraisam/__init__.py,sha256=TX0zdfnaVwhWCQr_w-RlsunG7Nw8dxv6vqCenWHQIp4,6145
36
37
  antares_devkit/filters/sample_filter/__init__.py,sha256=44bMq3-9hufcSm-Oz-tXpRLegiJjlFjhhkJCLEaX0QA,240
37
38
  antares_devkit/filters/siena_mag_coord_cut/__init__.py,sha256=e-DuypP8_FJenAZVT2YOEPi2-ZO_W5L9XuvtxUoiM08,1825
38
39
  antares_devkit/filters/sso/__init__.py,sha256=zCM_1pcNJm-BVpJ6-pRC-mvz2W1KfVmkp-JmK7I0V-I,8331
@@ -46,8 +47,9 @@ antares_devkit/filters/vpdf/__init__.py,sha256=tQv8gpbKuGRgZDhbsAlCc9JX8tygiK1wu
46
47
  antares_devkit/filters/vpdf/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
48
  antares_devkit/filters/vpdf/data/matheson_percent_grid_v1,sha256=hADpAh6hXh-7aZBt_KzDaIAMUBhBsOyx32HGFSqRLSk,23262120
48
49
  antares_devkit/filters/young_extragalactic_candidate/__init__.py,sha256=N0K91eTfxoGjSmt_8gav-MrtMC6J_8zZ1A5kjh6b3RE,5154
50
+ antares_devkit/filters/young_rubin_transients_soraisam/__init__.py,sha256=m9PWt7-IRIsQJehaZ1_h-3sz1QtwIHkHEY7J_AkgHrs,5008
49
51
  antares_devkit/models.py,sha256=Ghh6FxJnA8PlbebIwRcj23d5JCUS0YhhlqDTJ48xHj8,23298
50
- antares_devkit/utils.py,sha256=VwznaKG_VOiY7YGuCrzwc64ekmji5Jdd3dPRR1HYwcU,7195
52
+ antares_devkit/utils.py,sha256=-mHqoyccLjSZBldQnaQ3vE0Z3-e-2avXhnaBRvzYEG4,7379
51
53
  test/Dockerfile,sha256=NPbkb105rWXzgGf12GXNd5P6_it28XRSZ0ZleO7eTdc,473
52
54
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
55
  test/conftest.py,sha256=tMNd9DvUoDmTL3Z3WybbiQfs46cHWfDvkFSiXC05MQY,2835
@@ -58,4 +60,4 @@ test/unit/antares_devkit/filters/test_test_dev_lsst.py,sha256=EdgByUTs3zhJcNuPa9
58
60
  test/unit/antares_devkit/filters/test_test_dev_ztf.py,sha256=IBEV5lZ2ml1GFt9-ITew38ipoTiAvljYT_FFqQDWTO4,2069
59
61
  test/unit/antares_devkit/test_models.py,sha256=g0erQz6u2RnNcQurrDizmiQSB2vrU_9J6gvgdmO7Rp0,6604
60
62
  test/unit/test_filters.py,sha256=I-cGvPabN-uWcqHdXJP6u5nR0hi12F7vA_qGu5GiTRA,371
61
- antares_devkit-0.4.0.dist-info/RECORD,,
63
+ antares_devkit-0.5.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.4.6)
2
+ Generator: pdm-backend (2.4.7)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any