antares-devkit 0.7.1__tar.gz → 0.8.1__tar.gz

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.
Files changed (72) hide show
  1. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/PKG-INFO +2 -1
  2. antares_devkit-0.8.1/antares_devkit/filters/lantern/__init__.py +223 -0
  3. antares_devkit-0.8.1/antares_devkit/filters/lantern/data/lantern_xgboost_t2.0.7.pkl +0 -0
  4. antares_devkit-0.8.1/antares_devkit/filters/malanchev_features_v1/__init__.py +641 -0
  5. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/microlensing/__init__.py +82 -65
  6. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/models.py +7 -0
  7. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/utils.py +1 -0
  8. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/pyproject.toml +2 -1
  9. antares_devkit-0.8.1/test/__init__.py +0 -0
  10. antares_devkit-0.7.1/antares_devkit/filters/malanchev_features_v1/__init__.py +0 -1152
  11. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/LICENSE.txt +0 -0
  12. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/README.md +0 -0
  13. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/__init__.py +0 -0
  14. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/bad_detection/__init__.py +0 -0
  15. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/bad_seeing/__init__.py +0 -0
  16. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/crash_filter/__init__.py +0 -0
  17. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/decam_shadow/__init__.py +0 -0
  18. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/desi_target/__init__.py +0 -0
  19. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/dwarf_nova_outburst/__init__.py +0 -0
  20. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/ecl_transient_1/__init__.py +0 -0
  21. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/ecl_transient_2/__init__.py +0 -0
  22. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/extragalactic/__init__.py +0 -0
  23. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/highamp/__init__.py +0 -0
  24. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/highfluxchange/__init__.py +0 -0
  25. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/highsnr/__init__.py +0 -0
  26. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/if_anomaly_detection/__init__.py +0 -0
  27. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/if_anomaly_detection/data/__init__.py +0 -0
  28. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/if_anomaly_detection/data/paleo2_106IFmodel_472727objs_nest=1000_cont=0.001_transf.pkl +0 -0
  29. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/imbh/__init__.py +0 -0
  30. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/inm31/__init__.py +0 -0
  31. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/laiss_rfc_ad_filter/__init__.py +0 -0
  32. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/laiss_rfc_ad_filter/data/__init__.py +0 -0
  33. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/laiss_rfc_ad_filter/data/cls=binary_n_estimators=100_max_depth=35_rs=11_max_feats=35_cw=balanced.pkl +0 -0
  34. {antares_devkit-0.7.1/antares_devkit/filters/malanchev_anomaly_transient_dmdt → antares_devkit-0.8.1/antares_devkit/filters/lantern}/data/__init__.py +0 -0
  35. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/lsst_ddf/__init__.py +0 -0
  36. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/lsst_transient_quality_scimma/__init__.py +0 -0
  37. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/malanchev_anomaly_transient_dmdt/__init__.py +0 -0
  38. {antares_devkit-0.7.1/antares_devkit/filters/vpdf → antares_devkit-0.8.1/antares_devkit/filters/malanchev_anomaly_transient_dmdt}/data/__init__.py +0 -0
  39. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/malanchev_anomaly_transient_dmdt/data/malanchev_ssiforest_v1.pickle +0 -0
  40. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/novtest/__init__.py +0 -0
  41. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/nuclear_transient/__init__.py +0 -0
  42. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/nuttela_tao/__init__.py +0 -0
  43. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/persistent_dimmers/__init__.py +0 -0
  44. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/random_tagger_filter/__init__.py +0 -0
  45. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/recent_reddening/__init__.py +0 -0
  46. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/refitt_newsources_snrcut/__init__.py +0 -0
  47. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/rubin_NovTest_soraisam/__init__.py +0 -0
  48. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/sample_filter/__init__.py +0 -0
  49. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/shadow_virgo/__init__.py +0 -0
  50. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/siena_mag_coord_cut/__init__.py +0 -0
  51. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/sso/__init__.py +0 -0
  52. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/sub_lum/__init__.py +0 -0
  53. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/superphot_plus_v1/__init__.py +0 -0
  54. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/superphot_plus_ztf_v3/__init__.py +0 -0
  55. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/test_dev_all/__init__.py +0 -0
  56. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/test_dev_lsst/__init__.py +0 -0
  57. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/test_dev_ztf/__init__.py +0 -0
  58. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/uniform_random_sample/__init__.py +0 -0
  59. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/vpdf/__init__.py +0 -0
  60. {antares_devkit-0.7.1/test → antares_devkit-0.8.1/antares_devkit/filters/vpdf/data}/__init__.py +0 -0
  61. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/vpdf/data/matheson_percent_grid_v1 +0 -0
  62. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/young_extragalactic_candidate/__init__.py +0 -0
  63. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/antares_devkit/filters/young_rubin_transients_soraisam/__init__.py +0 -0
  64. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/Dockerfile +0 -0
  65. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/conftest.py +0 -0
  66. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/data/large_locus.py +0 -0
  67. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/data/small_locus.py +0 -0
  68. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/unit/antares_devkit/filters/test_test_dev_all.py +0 -0
  69. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/unit/antares_devkit/filters/test_test_dev_lsst.py +0 -0
  70. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/unit/antares_devkit/filters/test_test_dev_ztf.py +0 -0
  71. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/unit/antares_devkit/test_models.py +0 -0
  72. {antares_devkit-0.7.1 → antares_devkit-0.8.1}/test/unit/test_filters.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: antares-devkit
3
- Version: 0.7.1
3
+ Version: 0.8.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>
@@ -51,6 +51,7 @@ 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
53
  Requires-Dist: slack-sdk>=3.39.0; extra == "filter-dependencies"
54
+ Requires-Dist: xgboost==2.1.4; extra == "filter-dependencies"
54
55
  Provides-Extra: jupyter
55
56
  Requires-Dist: matplotlib>=3.9.4; extra == "jupyter"
56
57
  Description-Content-Type: text/markdown
@@ -0,0 +1,223 @@
1
+ from antares_devkit.models import BaseFilter
2
+ from antares_devkit.filters.lantern import data
3
+
4
+ class Lantern(BaseFilter):
5
+
6
+ SLACK_CHANNEL = '#filter-lantern'
7
+ TRIGGERING_SURVEY = 'lsst'
8
+ # REQUIRED_LOCUS_PROPERTIES = []
9
+ REQUIRED_ALERT_PROPERTIES = [
10
+ 'lsst_diaSource_band',
11
+ 'lsst_diaSource_snr',
12
+ 'lsst_diaSource_scienceFlux',
13
+ 'lsst_diaSource_psfFlux',
14
+ 'lsst_diaSource_apFlux',
15
+ 'lsst_diaSource_psfChi2',
16
+ 'lsst_diaSource_dipoleFitAttempted',
17
+ ]
18
+ # REQUIRED_TAGS = []
19
+ OUTPUT_LOCUS_PROPERTIES = [
20
+ {
21
+ 'name': 'lantern_xgboost_t2.0.7_c0.95_num_tagged_alerts',
22
+ 'type': 'int',
23
+ 'description': 'number of alerts associated with this locus which have passed this version of the lantern First Cut filter',
24
+ },
25
+ {
26
+ 'name': 'lantern_xgboost_t2.0.7_c0.95_max_score',
27
+ 'type': 'float',
28
+ 'description': 'maximum lantern score of all alerts associated with this locus which have passed this version of the lantern First Cut filter',
29
+ },
30
+ ]
31
+
32
+ OUTPUT_LOCUS_TAGS = [
33
+ {
34
+ 'name': 'lantern_xgboost_t2.0.7_c0.95',
35
+ 'description': 'locus has one or more Alerts identified by this version of lantern as a First Cut LAGN target, based on threshold for Y2 0.95 completeness.'
36
+ },
37
+ ]
38
+
39
+ REQUIRES_FILES = [
40
+ 'lantern_xgboost_t2.0.7.pkl',
41
+ ]
42
+
43
+ def setup(self):
44
+ """
45
+ ANTARES will call this function once at the beginning of each night when filters
46
+ are loaded.
47
+ """
48
+ import pickle
49
+ from importlib.resources import open_binary
50
+ import xgboost
51
+
52
+ with open_binary(data, 'lantern_xgboost_t2.0.7.pkl') as f:
53
+ self.lantern_model = pickle.load(f)
54
+
55
+ self.threshold = 0.9691 #currently set for completeness 0.95
56
+
57
+ def _run(self, locus):
58
+ """
59
+ ANTARES will call this function in real-time for each incoming Alert.
60
+ """
61
+
62
+ import xgboost
63
+ import numpy as np
64
+ import pandas as pd
65
+
66
+ def get_prop(name):
67
+ if locus.alert.properties.get(name) is not None:
68
+ val = locus.alert.properties[name]
69
+ else:
70
+ val = np.nan
71
+ return val
72
+
73
+ # Extract direct alert properties
74
+ band = get_prop('lsst_diaSource_band')
75
+ snr = get_prop('lsst_diaSource_snr')
76
+ scienceFlux = get_prop('lsst_diaSource_scienceFlux')
77
+ psfFlux = get_prop('lsst_diaSource_psfFlux')
78
+ apFlux = get_prop('lsst_diaSource_apFlux')
79
+ extendedness = get_prop('lsst_diaSource_extendedness')
80
+ psfChi2 = get_prop('lsst_diaSource_psfChi2')
81
+ dipoleFitAttempted = get_prop('lsst_diaSource_dipoleFitAttempted')
82
+ dipoleChi2 = get_prop('lsst_diaSource_dipoleChi2')
83
+ dipoleLength = get_prop('lsst_diaSource_dipoleLength')
84
+
85
+ # Calculate engineered features
86
+ engineered = self._add_engineered_features(locus)
87
+
88
+ # Create DataFrame with the same structure as model training
89
+ feature_dict = {
90
+ 'band': [band],
91
+ 'psf_fwhm': [engineered['psf_fwhm']],
92
+ 'snr': [snr],
93
+ 'template_flux': [engineered['template_flux']],
94
+ 'scienceFlux': [scienceFlux],
95
+ 'psfFlux': [psfFlux],
96
+ 'apFlux': [apFlux],
97
+ 'temp_sci_flux_ratio': [engineered['temp_sci_flux_ratio']],
98
+ 'moment_ext': [engineered['moment_ext']],
99
+ 'ellip_ext': [engineered['ellip_ext']],
100
+ 'flux_ext': [engineered['flux_ext']],
101
+ 'extendedness': [extendedness],
102
+ 'psfChi2': [psfChi2],
103
+ 'dipoleFitAttempted': [dipoleFitAttempted],
104
+ 'dipoleChi2': [dipoleChi2],
105
+ 'dipoleLength': [dipoleLength],
106
+ 'x_y_err': [engineered['x_y_err']],
107
+ }
108
+
109
+ # Preprocessing for bands and flags
110
+ def normalize_bands_and_flags(df):
111
+ """Normalizes band strings and converts flag columns. Returns a copy."""
112
+ df = df.copy()
113
+ if 'band' in df.columns:
114
+ # Handle both FilterLabel(band="g", ...) and plain 'g' formats
115
+ extracted = df['band'].astype(str).str.extract(r"band=['\"]([ugrizy])['\"]", expand=False)
116
+ # Fall back to bare letter for rows already in plain format
117
+ plain = df['band'].astype(str).str.extract(r'^([ugrizy])$', expand=False)
118
+ df['band'] = extracted.fillna(plain)
119
+ # XGBoost requires categorical columns to be the 'category' dtype
120
+ df['band'] = df['band'].astype('category')
121
+ flag_cols = [c for c in df.columns if 'flag' in c.lower() or c in ['isDipole']]
122
+ for col in flag_cols:
123
+ df[col] = df[col].astype(bool)
124
+ return df
125
+
126
+ df = normalize_bands_and_flags(pd.DataFrame(feature_dict))
127
+
128
+ # Get prediction probability
129
+ prediction_proba = self.lantern_model.predict_proba(df)[0, 1]
130
+
131
+ if prediction_proba >= self.threshold:
132
+ locus.tag('lantern_xgboost_t2.0.7_c0.95')
133
+
134
+ #track number of tagged alerts
135
+ if 'lantern_xgboost_t2.0.7_c0.95_num_tagged_alerts' in locus.properties:
136
+ n = locus.properties['lantern_xgboost_t2.0.7_c0.95_num_tagged_alerts']
137
+ n += 1
138
+ else:
139
+ n = 1
140
+
141
+ locus.set_property('lantern_xgboost_t2.0.7_c0.95_num_tagged_alerts', n)
142
+
143
+ #track maximum score
144
+ if 'lantern_xgboost_t2.0.7_c0.95_max_score' in locus.properties:
145
+ old_score = locus.properties['lantern_xgboost_t2.0.7_c0.95_max_score']
146
+ #only update if new score is larger than old score
147
+ if prediction_proba > old_score:
148
+ locus.set_property('lantern_xgboost_t2.0.7_c0.95_max_score', float(prediction_proba))
149
+ else:
150
+ locus.set_property('lantern_xgboost_t2.0.7_c0.95_max_score', float(prediction_proba))
151
+
152
+ def _add_engineered_features(self, locus):
153
+ """
154
+ Calculate engineered features from a single alert.
155
+
156
+ Returns
157
+ -------
158
+ dict
159
+ Dictionary of engineered features
160
+ """
161
+ import numpy as np
162
+
163
+ def get_prop(name):
164
+ if locus.alert.properties.get(name) is not None:
165
+ val = locus.alert.properties[name]
166
+ else:
167
+ val = np.nan
168
+ return val
169
+
170
+ # Calculate moment extension
171
+ psf_trace = get_prop('lsst_diaSource_ixxPSF') + get_prop('lsst_diaSource_iyyPSF')
172
+ src_trace = get_prop('lsst_diaSource_ixx') + get_prop('lsst_diaSource_iyy')
173
+ moment_ext = src_trace / psf_trace if psf_trace != 0 else np.nan
174
+
175
+ # Calculate ellipticity extension
176
+ ixx = get_prop('lsst_diaSource_ixx')
177
+ iyy = get_prop('lsst_diaSource_iyy')
178
+ ixy = get_prop('lsst_diaSource_ixy')
179
+ ixxPSF = get_prop('lsst_diaSource_ixxPSF')
180
+ iyyPSF = get_prop('lsst_diaSource_iyyPSF')
181
+ ixyPSF = get_prop('lsst_diaSource_ixyPSF')
182
+
183
+ if src_trace != 0:
184
+ src_ellip = np.sqrt((ixx - iyy)**2 + 4 * ixy**2) / src_trace
185
+ else:
186
+ src_ellip = np.nan
187
+
188
+ if psf_trace != 0:
189
+ psf_ellip = np.sqrt((ixxPSF - iyyPSF)**2 + 4 * ixyPSF**2) / psf_trace
190
+ else:
191
+ psf_ellip = np.nan
192
+
193
+ ellip_ext = src_ellip - psf_ellip
194
+
195
+ # Calculate flux extension
196
+ psfFlux = get_prop('lsst_diaSource_psfFlux')
197
+ apFlux = get_prop('lsst_diaSource_apFlux')
198
+ flux_ext = apFlux / psfFlux if psfFlux != 0 else np.nan
199
+
200
+ # Calculate template flux ratio
201
+ scienceFlux = get_prop('lsst_diaSource_scienceFlux')
202
+ template_flux = scienceFlux - psfFlux
203
+ temp_sci_flux_ratio = template_flux / scienceFlux if scienceFlux != 0 else np.nan
204
+
205
+ # Calculate PSF FWHM
206
+ psf_det = ixxPSF * iyyPSF - ixyPSF**2
207
+ psf_fwhm = np.abs(psf_det)**(1/4) * 2.35482 * 0.2 if psf_det != 0 else np.nan
208
+
209
+ # Calculate x-y error
210
+ xErr = get_prop('lsst_diaSource_xErr')
211
+ yErr = get_prop('lsst_diaSource_yErr')
212
+ x_y_err = np.sqrt(xErr**2 + yErr**2)
213
+
214
+ # Return as dictionary
215
+ return {
216
+ 'moment_ext': moment_ext,
217
+ 'ellip_ext': ellip_ext,
218
+ 'flux_ext': flux_ext,
219
+ 'template_flux': template_flux,
220
+ 'temp_sci_flux_ratio': temp_sci_flux_ratio,
221
+ 'psf_fwhm': psf_fwhm,
222
+ 'x_y_err': x_y_err
223
+ }