jacscanomaly 0.3.0__tar.gz → 0.3.2__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 (52) hide show
  1. jacscanomaly-0.3.2/MANIFEST.in +1 -0
  2. jacscanomaly-0.3.2/PKG-INFO +418 -0
  3. jacscanomaly-0.3.2/README.md +388 -0
  4. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/pyproject.toml +33 -2
  5. jacscanomaly-0.3.2/setup.py +25 -0
  6. jacscanomaly-0.3.2/src/jacscanomaly/__init__.py +58 -0
  7. jacscanomaly-0.3.2/src/jacscanomaly/_cpp_grid.cpp +780 -0
  8. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/config.py +147 -6
  9. jacscanomaly-0.3.2/src/jacscanomaly/criteria.py +36 -0
  10. jacscanomaly-0.3.2/src/jacscanomaly/finder.py +712 -0
  11. jacscanomaly-0.3.2/src/jacscanomaly/magnification.py +29 -0
  12. jacscanomaly-0.3.2/src/jacscanomaly/models.py +242 -0
  13. jacscanomaly-0.3.2/src/jacscanomaly/parallax.py +612 -0
  14. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/plot.py +176 -17
  15. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/runner.py +187 -33
  16. jacscanomaly-0.3.2/src/jacscanomaly/singlelens_fit.py +910 -0
  17. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/singlelens_model.py +38 -1
  18. jacscanomaly-0.3.2/src/jacscanomaly/template_free.py +407 -0
  19. jacscanomaly-0.3.2/src/jacscanomaly/trajectory.py +91 -0
  20. jacscanomaly-0.3.2/src/jacscanomaly.egg-info/PKG-INFO +418 -0
  21. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly.egg-info/SOURCES.txt +14 -1
  22. jacscanomaly-0.3.2/src/jacscanomaly.egg-info/requires.txt +20 -0
  23. jacscanomaly-0.3.2/tests/test_config.py +27 -0
  24. jacscanomaly-0.3.2/tests/test_criteria.py +41 -0
  25. jacscanomaly-0.3.2/tests/test_extract.py +36 -0
  26. jacscanomaly-0.3.2/tests/test_models.py +87 -0
  27. jacscanomaly-0.3.2/tests/test_photometry.py +25 -0
  28. jacscanomaly-0.3.2/tests/test_seasons.py +39 -0
  29. jacscanomaly-0.3.2/tests/test_space_parallax.py +393 -0
  30. jacscanomaly-0.3.2/tests/test_template_free.py +30 -0
  31. jacscanomaly-0.3.0/PKG-INFO +0 -236
  32. jacscanomaly-0.3.0/README.md +0 -218
  33. jacscanomaly-0.3.0/src/jacscanomaly/__init__.py +0 -29
  34. jacscanomaly-0.3.0/src/jacscanomaly/finder.py +0 -383
  35. jacscanomaly-0.3.0/src/jacscanomaly/magnification.py +0 -16
  36. jacscanomaly-0.3.0/src/jacscanomaly/models.py +0 -106
  37. jacscanomaly-0.3.0/src/jacscanomaly/parallax.py +0 -258
  38. jacscanomaly-0.3.0/src/jacscanomaly/singlelens_fit.py +0 -352
  39. jacscanomaly-0.3.0/src/jacscanomaly/trajectory.py +0 -55
  40. jacscanomaly-0.3.0/src/jacscanomaly.egg-info/PKG-INFO +0 -236
  41. jacscanomaly-0.3.0/src/jacscanomaly.egg-info/requires.txt +0 -4
  42. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/LICENSE +0 -0
  43. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/setup.cfg +0 -0
  44. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/anomaly_models.py +0 -0
  45. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/data/__init__.py +0 -0
  46. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/data/earth_orbital_parallax_table.txt +0 -0
  47. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/extract.py +0 -0
  48. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/objective.py +0 -0
  49. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/photometry.py +0 -0
  50. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly/seasons.py +0 -0
  51. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly.egg-info/dependency_links.txt +0 -0
  52. {jacscanomaly-0.3.0 → jacscanomaly-0.3.2}/src/jacscanomaly.egg-info/top_level.txt +0 -0
@@ -0,0 +1 @@
1
+ include src/jacscanomaly/_cpp_grid.cpp
@@ -0,0 +1,418 @@
1
+ Metadata-Version: 2.4
2
+ Name: jacscanomaly
3
+ Version: 0.3.2
4
+ Summary: JAX-based scan anomaly detection for time-series residuals
5
+ Author: Kansuke Nunota
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/NunotaKansuke/jacscanomaly
8
+ Project-URL: Repository, https://github.com/NunotaKansuke/jacscanomaly
9
+ Project-URL: Issues, https://github.com/NunotaKansuke/jacscanomaly/issues
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: numpy
14
+ Requires-Dist: jax
15
+ Requires-Dist: jaxopt
16
+ Requires-Dist: matplotlib
17
+ Provides-Extra: docs
18
+ Requires-Dist: sphinx>=7; extra == "docs"
19
+ Requires-Dist: sphinx-rtd-theme>=2; extra == "docs"
20
+ Requires-Dist: myst-parser>=2; extra == "docs"
21
+ Provides-Extra: test
22
+ Requires-Dist: pytest>=7; extra == "test"
23
+ Requires-Dist: coverage[toml]>=7; extra == "test"
24
+ Provides-Extra: vbm
25
+ Requires-Dist: scipy; extra == "vbm"
26
+ Requires-Dist: VBMicrolensing; extra == "vbm"
27
+ Provides-Extra: dev
28
+ Requires-Dist: jacscanomaly[docs,test,vbm]; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # jacscanomaly
32
+
33
+ [![Documentation Status](https://readthedocs.org/projects/jacscanomaly/badge/?version=latest)](https://jacscanomaly.readthedocs.io/en/latest/?badge=latest)
34
+
35
+ **jacscanomaly** is a Python package for scan-based anomaly detection
36
+ in time-series light curves.
37
+
38
+ The package is designed to detect **microlensing planetary anomalies** by
39
+ scanning residuals after fitting a single lens model (e.g., PSPL),
40
+ with low-memory C++ backends for large survey light curves and JAX-based
41
+ fitters for flexible model development.
42
+
43
+ ---
44
+
45
+ ## Features
46
+
47
+ * **Scan-based anomaly detection** on residuals after single-lens fitting
48
+ * **C++ survey backends** for the PSPL fit and anomaly grid scan
49
+ * **JAX model components** for flexible single-lens and higher-order models
50
+ * **Candidate quality diagnostics**: effective contributing points,
51
+ peak-contribution fraction, and time-correlation metrics
52
+ * **Built-in visualization**: PSPL fit, residuals, and anomaly scan summary
53
+
54
+ ---
55
+
56
+ ## Documentation
57
+
58
+ The full documentation is available on ReadTheDocs:
59
+
60
+ https://jacscanomaly.readthedocs.io/en/latest/
61
+
62
+ Start with:
63
+
64
+ * [Installation](https://jacscanomaly.readthedocs.io/en/latest/installation.html)
65
+ * [Quickstart](https://jacscanomaly.readthedocs.io/en/latest/quickstart.html)
66
+ * [Examples](https://jacscanomaly.readthedocs.io/en/latest/examples.html)
67
+ * [Method overview](https://jacscanomaly.readthedocs.io/en/latest/method.html)
68
+ * [API reference](https://jacscanomaly.readthedocs.io/en/latest/api.html)
69
+
70
+ ---
71
+
72
+ ## Installation
73
+
74
+ ```bash
75
+ pip install jacscanomaly
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Quick Example
81
+
82
+ ```python
83
+ import numpy as np
84
+ import matplotlib.pyplot as plt
85
+ from jacscanomaly import CandidateCriteria, Finder, FinderConfig
86
+
87
+ # load data (time, flux, flux_err)
88
+ data = np.load("example_data.npy")
89
+ time, flux, ferr = data[:, 0], data[:, 1], data[:, 2]
90
+
91
+ # run anomaly finder
92
+ config = FinderConfig(
93
+ fitter_kind="pspl",
94
+ candidate_criteria=CandidateCriteria(min_n_eff=2.0),
95
+ )
96
+ finder = Finder(config)
97
+ result = finder.run(time, flux, ferr)
98
+
99
+ # You can still pass an explicit initial guess if desired:
100
+ # p0 = np.array([10000, 10, 0.3])
101
+ # result = finder.run(time, flux, ferr, p0)
102
+
103
+ result.print_summary()
104
+
105
+ # In notebooks, get a one-row table:
106
+ # display(result.summary_table())
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Visualization
112
+
113
+ ```python
114
+ finder.plot_result()
115
+ finder.plot_anomaly_window()
116
+ plt.show()
117
+ ```
118
+
119
+ These commands produce two complementary visualizations:
120
+
121
+ 1. **Three-panel summary plot (`finder.plot_result`)**
122
+
123
+ * **Top:** Observed light curve with the best-fit baseline model (PSPL)
124
+ * **Middle:** Residuals after baseline fitting
125
+ * **Bottom:** Anomaly scan result (Δχ² vs. time), showing where localized
126
+ deviations from the baseline model are detected
127
+
128
+ 2. **Focused anomaly window plot (`finder.plot_anomaly_window`)**
129
+
130
+ * A zoomed-in view around the best anomaly candidate
131
+ * Residuals are shown together with the anomaly template and the flat model
132
+
133
+ Example notebooks are available in `example/`:
134
+
135
+ * `template_scan_example.ipynb` for the standard bell-template scan
136
+ * `template_free_example.ipynb` for the template-free residual chi-square scan
137
+
138
+ ---
139
+
140
+ ## Method Overview
141
+
142
+ The workflow of `jacscanomaly` is:
143
+
144
+ 1. **First fitting**
145
+ Fit a single lens model (e.g. PSPL) to the full light curve.
146
+
147
+ 2. **Residual analysis**
148
+ Compute residuals:
149
+
150
+ ```
151
+ residual = data − single_lens_model
152
+ ```
153
+
154
+ 3. **Local anomaly scan**
155
+ For each grid point `(t0, teff)`, compare:
156
+
157
+ * a flat model
158
+ * an anomaly template model
159
+ within a local time window.
160
+
161
+ 4. **Detection statistic**
162
+ The improvement is measured by:
163
+
164
+ ```
165
+ Δχ² = χ²_flat − χ²_anomaly
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Anomaly Score
171
+
172
+ To quantify how significant the best anomaly candidate is relative to others,
173
+ we define a **score**:
174
+
175
+ ```
176
+ score = (Δχ²_best − median(Δχ²_others)) / std(Δχ²_others)
177
+ ```
178
+
179
+ In practice, `jacscanomaly` estimates `median(Δχ²_others)` and
180
+ `std(Δχ²_others)` from the bulk of the other cluster peaks, trimming values
181
+ above `best_score_trim_percentile` first when possible. This makes the score
182
+ less sensitive to a few strong secondary peaks.
183
+
184
+ This measures how strongly the best candidate stands out from the rest of the grid.
185
+
186
+ ---
187
+
188
+ ## Candidate Quality Diagnostics
189
+
190
+ Large Δχ² values can sometimes be dominated by one or two points. To make this
191
+ visible, `jacscanomaly` stores per-candidate support diagnostics in
192
+ `result.best.quality` and per-grid diagnostics in `result.grid_metrics_all`.
193
+
194
+ For the best candidate:
195
+
196
+ ```python
197
+ q = result.best.quality
198
+ print(q.n_window) # points in the local chi2 window
199
+ print(q.n_contrib) # points above the per-point improvement threshold
200
+ print(q.n_eff) # effective number of contributing points
201
+ print(q.peak_frac) # strongest-point fraction of total positive improvement
202
+ print(q.rho1) # lag-1 autocorrelation of per-point improvements
203
+ print(q.longest_run) # longest consecutive run of contributing points
204
+ ```
205
+
206
+ The effective point count is computed from positive per-point improvements
207
+ using a participation-ratio style statistic:
208
+
209
+ ```
210
+ n_eff = (sum_i u_i)^2 / sum_i u_i^2
211
+ ```
212
+
213
+ where `u_i = max(0, chi2_flat_i - chi2_anomaly_i)`. A one-point-dominated
214
+ candidate has `n_eff` close to 1 and a large `peak_frac`.
215
+
216
+ `result.grid_metrics_all` is a NumPy array with columns:
217
+
218
+ ```
219
+ [t0, teff, dchi2, n_window, n_contrib, n_eff, peak_frac, rho1, longest_run]
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Result Summaries
225
+
226
+ `AnomalyResult` provides both CLI-friendly and notebook-friendly summaries:
227
+
228
+ ```python
229
+ result.print_summary() # print formatted text
230
+ text = result.summary_text() # return formatted text
231
+ row = result.summary_dict() # return a plain dictionary
232
+ table = result.summary_table() # pandas.DataFrame when pandas is installed
233
+ ```
234
+
235
+ `print(result)` also shows the formatted summary text.
236
+
237
+ ---
238
+
239
+ ## Configuration
240
+
241
+ Key parameters are controlled via `FinderConfig`:
242
+
243
+ ```python
244
+ from jacscanomaly import CandidateCriteria, FinderConfig
245
+
246
+ config = FinderConfig(
247
+ grid_backend="cpp", # default for PSPL survey scans
248
+ single_fit_backend="cpp",
249
+ teff_init=0.03, # initial anomaly timescale
250
+ teff_grid_n=20, # number of teff grid points
251
+ sigma=3.0, # per-point improvement threshold for n_contrib
252
+ candidate_criteria=CandidateCriteria(min_n_eff=2.0),
253
+ best_score_trim_percentile=95.0, # trim upper tail for best-candidate score
254
+ )
255
+ ```
256
+
257
+ See `FinderConfig` for the full list of options.
258
+
259
+ For finite-source single-lens baselines without JAX autodiff, use the
260
+ VBMicrolensing finite-difference fitters:
261
+
262
+ ```python
263
+ config = FinderConfig(
264
+ fitter_kind="fspl_vbm_fd",
265
+ grid_backend="cpp",
266
+ )
267
+ ```
268
+
269
+ For GULLS-convention spacecraft parallax:
270
+
271
+ ```python
272
+ config = FinderConfig(
273
+ fitter_kind="fspl_space_parallax_gulls_vbm_fd",
274
+ grid_backend="cpp",
275
+ ra_deg=267.3,
276
+ dec_deg=-29.9,
277
+ tref=2461504.0,
278
+ satellite_ephemeris_path="gulls_orbit5_heliocentric.dat",
279
+ )
280
+ ```
281
+
282
+ These fitters evaluate finite-source magnification with
283
+ `VBMicrolensing.ESPLMag` and optimize nonlinear parameters with SciPy
284
+ finite-difference least squares. They are useful for large CPU survey runs
285
+ where JAX FSPL autodiff overhead dominates runtime.
286
+
287
+ ---
288
+
289
+ ## Example Data
290
+
291
+ The light curves used as examples in this repository are drawn from an original set of
292
+ **2,371 simulated Roman light curves** generated by the **Roman Galactic Exoplanet Survey
293
+ Project Infrastructure Team (RGES PIT)**, **WG07 Survey Simulations and Pipeline Validation**
294
+ (Farzaneh Zohrabi, Matthew Penny, Macy Huston, Ali Crisp, et al).
295
+
296
+ This representative sample of 2,371 light curves was selected assuming the **Cassan exoplanet
297
+ mass function** and consists of simulated Roman light curves of **planetary microlensing events**,
298
+ including higher-order effects such as **parallax** and **orbital motion**.
299
+
300
+ ---
301
+
302
+ ## Algorithmic Background
303
+
304
+ The anomaly scan implemented in `jacscanomaly` is inspired by the
305
+ systematic anomaly search methodology developed for microlensing surveys
306
+ (e.g., the KMTNet AnomalyFinder series). In particular, the approach
307
+ of scanning residual light curves over a grid of anomaly times and
308
+ durations is based on key ideas presented in:
309
+
310
+ > Zang, W., Jung, Y., Yee, J., et al. (2021). *Systematic KMTNet Planetary
311
+ > Anomaly Search, Paper I: OGLE-2019-BLG-1053Lb, A Buried Terrestrial
312
+ > Planet*. The Astronomical Journal, **162**, 163.
313
+ > DOI: 10.3847/1538-3881/ac12d4 :contentReference[oaicite:3]{index=3}
314
+
315
+ This work described a semi-automated search algorithm that iteratively
316
+ scans events for localized deviations relative to a baseline model and
317
+ quantifies the significance of detected signals — an idea that is central
318
+ to the grid-scan and Δχ² evaluation in `jacscanomaly`.
319
+
320
+ ---
321
+
322
+ ### Finite-source magnification (FSPL)
323
+
324
+ `jacscanomaly` provides two FSPL implementation families:
325
+
326
+ * JAX/microjax fitters: `fspl`, `fspl_parallax`, and `fspl_space_parallax`.
327
+ * CPU finite-difference fitters using VBMicrolensing ESPL magnification:
328
+ `fspl_vbm_fd` and `fspl_space_parallax_gulls_vbm_fd`.
329
+
330
+ Install the VBM backend dependencies with:
331
+
332
+ ```bash
333
+ pip install -e ".[vbm]"
334
+ ```
335
+
336
+ The VBM fitters keep the anomaly grid scan in the compiled C++ backend when
337
+ `grid_backend="cpp"` is selected.
338
+
339
+ For the JAX/microjax FSPL fitters, finite-source magnifications are computed
340
+ using an external JAX-based implementation.
341
+
342
+ The original FFT-based extended-source algorithm is from:
343
+ https://github.com/git-sunao/fft-extended-source
344
+
345
+ This algorithm is provided in JAX form by:
346
+ https://github.com/ShotaMiyazaki94/microjax
347
+
348
+ Specifically, `jacscanomaly` uses the FFT disk-integration implementation
349
+ available through:
350
+
351
+ from microjax.fastlens import fspl_disk
352
+
353
+ Note:
354
+ `jacscanomaly` currently requires the GitHub source version of `microjax`.
355
+ The PyPI package `microjaxx==0.1.1` may not expose
356
+ `microjax.fastlens.fspl_disk`.
357
+
358
+ Install `microjax` from source before using FSPL functionality:
359
+
360
+ git clone https://github.com/ShotaMiyazaki94/microjax.git
361
+ cd microjax
362
+ python -m pip install -e .
363
+
364
+ You can verify the installation with:
365
+
366
+ from microjax.fastlens import fspl_disk
367
+
368
+ ## Citation
369
+
370
+ If you use **jacscanomaly** in academic work, including journal articles,
371
+ conference proceedings, or theses, please cite the software.
372
+
373
+ Citation metadata is provided in the `citation.cff` file in this repository,
374
+ which can be used directly by GitHub and reference managers.
375
+
376
+ ---
377
+
378
+ ## Requirements
379
+
380
+ * Python ≥ 3.9
381
+ * numpy
382
+ * jax
383
+ * jaxopt
384
+ * matplotlib
385
+
386
+ Optional for VBM finite-difference FSPL fitters:
387
+
388
+ * scipy
389
+ * VBMicrolensing
390
+
391
+ ---
392
+
393
+ ## Development
394
+
395
+ Install the package with development dependencies:
396
+
397
+ ```bash
398
+ pip install -e ".[dev]"
399
+ ```
400
+
401
+ Run the unit tests:
402
+
403
+ ```bash
404
+ pytest
405
+ ```
406
+
407
+ Run the tests with coverage:
408
+
409
+ ```bash
410
+ coverage run -m pytest
411
+ coverage report
412
+ ```
413
+
414
+ Build the Sphinx documentation locally:
415
+
416
+ ```bash
417
+ sphinx-build -W -b html docs docs/_build/html
418
+ ```