diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a7731b9..2e6c5e7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -48,6 +48,7 @@ What's new in cuvarbase * CE is now in **maintenance mode**: it keeps working, but no new development is planned — for an actively developed GPU CE/AOV search see `periodfind `_ * **Experimental** (UserWarning on import; not recommended for science use yet) * GPU Transit Least Squares (``cuvarbase.tls``) with Ofir (2014) period grids + * **TLS rewritten for survey-scale throughput (Jul 2026):** a new batch-native fast path (``tls_fast.cu`` + ``tls_search_batch()``) is now the default for ``tls_search``/``tls_search_gpu``/``tls_transit`` (opt out with ``use_fast=False``). Each (lightcurve, period) block folds once into shared-memory phase bins and scans every (duration, t0) trial against bin-averaged integrated-template tables with a closed-form chi2 (``chi2 = chi2_0 - num^2/den``), so trial cost is independent of ndata — the legacy kernel's two full O(ndata) passes per trial and its ~3,500-point shared-memory cap are both gone (Kepler-length and 2-min-cadence TESS lightcurves run natively). The period grid is split into bin-count bands so long-period searches don't pay the finest band's cost; folding uses an exact float-float decomposition (~1e-8 phase error at 4-year baselines, no 1/64-rate double math); the kernel outputs the cancellation-free delta-chi2 and the host reconstructs chi2 in float64. A second exact kernel re-fits the top-K candidate periods per lightcurve on a finer local (duration, t0) grid (``refine_top_k``, default 50; ``refine_oversample`` default 33, near the reference package's t0 stepping) — refinement sharpens the reported parameters while the SDE/FAP statistics come from the uniform coarse spectrum, keeping the detection statistic's scale consistent with the legacy kernel (chi2 correlation 0.998 measured). SDE detrending now uses the reference ``transitleastsquares`` 91-point median window instead of a pathological ``nperiods/10`` window (minutes -> ~0.1 s at 190k periods), ``duration_grid_keplerian`` is vectorized (1.1 s -> 40 ms at 190k periods), and per-lightcurve statistics run on a thread pool. Measured end-to-end on an RTX A5000 (``scripts/benchmark_tls_survey.py``, 100% injected-transit recovery in every regime): TESS-FFI sector 1.2 ms/lightcurve (~800 LC/s), K2 90-d 3.1 ms, TESS 2-min 2.8 ms, 1-yr/30-min 18 ms, Kepler 4-yr/65k-pt/172k-period 0.17 s/LC. **Fidelity is not sacrificed for detection:** on the identical SDE statistic (recomputed on each method's chi2 spectrum), the default coarse-epoch grid gives SDE within 1-3% of the reference ``transitleastsquares`` package (0.97-0.99x) with 100% recovery including marginal-depth and narrow transits, because SDE is a period-space contrast largely insensitive to epoch-grid density; a reference-matched epoch grid (``t0_oversample=33``) closes it to within 1% (1.01-1.03x) at a measured 6-15x cost, and the exact refinement restores per-transit t0/parameter precision regardless. Apples-to-apples on the same machine (same light curves, same grid, single GPU vs all CPU cores), cuvarbase is ~1,000-3,000x faster than the reference at matched SDE fidelity; on a Kepler-class configuration it is ~22x (matched) to ~190x (default) faster than the concurrent GTLS CuPy GPU-TLS (arXiv:2607.00348, 33-138 s/LC on a faster RTX 4090). See ``analysis/TLS_COST_ANALYSIS.md``. Batch API validation: empty/mismatched inputs, ``qmax < 1``, power-of-two ``block_size``, and non-negative ``refine_top_k`` are enforced with clear errors; offsets are 64-bit so >2^31-point batches chunk correctly * TLS epoch (t0) grid is now duration-scaled (stride = duration / oversample, floor 30, cap 20,000 epochs): the previous fixed 30-epoch grid missed transits narrower than ~1/30 of the period entirely, which broke Keplerian-mode searches for most periods > ~3.5 d. The oversample factor is caller-tunable via ``t0_oversample`` on ``tls_search``/``tls_search_gpu``/``compile_tls`` (default 3.0, favoring speed; the reference ``transitleastsquares`` steps ~33x finer — raise it for sensitivity-critical searches). Mirrored in ``tls_grids.t0_grid_size()`` * Removed the TLS kernels' bitonic phase sort: it was incomplete for non-power-of-2 sizes and its output order was never consumed — pure wasted per-period work; results are unchanged * Added golden accuracy tests against the reference ``transitleastsquares`` package (``test_tls_golden.py``) diff --git a/README.md b/README.md index d469c0c..ed4a419 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ cuvarbase is built for processing millions of lightcurves, and it is proven in p The headline numbers, all traceable to benchmark data in this repository: - **Standard BLS is 257-354x faster than astropy's `BoxLeastSquares`**, measured consistently across all 7 GPU architectures tested (V100 through H200) +- **Transit Least Squares is 30-170x faster than GTLS** — the only other GPU TLS — on the same GPU at matched search settings and equal (1-3%) detection significance, and thousands of times faster than the reference CPU `transitleastsquares` ([details](#transit-least-squares-tls)) - **Keplerian frequency grids search 4-37x fewer frequencies** than uniform grids at survey baselines by exploiting the orbital-mechanics link between period and transit duration - **All four major surveys for ~$33 of GPU time**: running both Lomb-Scargle and BLS over ZTF + HAT-Net + TESS + Kepler scale lightcurve collections costs roughly $33 total on a rented RTX A5000 at $0.20/hr (tables below) @@ -41,6 +42,18 @@ frequencies, single lightcurves), nifty-ls on CPU is faster than cuvarbase's GPU LS — the GPU advantage appears at survey-scale frequency grids (>~100K frequencies) and batched workloads. Use nifty-ls for one-off small searches. +### Transit Least Squares (TLS) + +cuvarbase's survey-scale TLS ([Hippke & Heller 2019](https://ui.adsabs.harvard.edu/abs/2019A%26A...623A..39H/abstract)) is, to our knowledge, the fastest GPU TLS available. Reproducing the benchmark from the GTLS paper ([arXiv:2607.00348](https://arxiv.org/abs/2607.00348)) apples-to-apples on one RTX A5000 — identical Ofir period grid, matched per-period duration window, matched epoch density, one injected transit — cuvarbase-TLS is **30–170x faster than GTLS** over 200–2000 day baselines (the gap grows with baseline), at **1–3% detection-significance (SDE) parity** and 100% recovery: + +| Baseline | GTLS | cuvarbase TLS | Speedup | +|--------|-------:|-------------:|--------:| +| 200 d | 4.1 s | 0.14 s | **30x** | +| 1000 d | 75.8 s | 0.88 s | **86x** | +| 2000 d | 348 s | 2.0 s | **171x** | + +It also beats GTLS's *own* published RTX-4090 numbers by 23–40x from a slower A5000, and runs thousands of times faster than the reference CPU `transitleastsquares`. Full methodology and the reproduced figure: [analysis/GTLS_COMPARISON.md](analysis/GTLS_COMPARISON.md). + See [docs/BENCHMARK_RESULTS.md](docs/BENCHMARK_RESULTS.md) for methodology, competitive analysis, and cost projections. ## About @@ -76,12 +89,17 @@ This module ships in this release but has **known correctness issues** and is not recommended for science use yet. It emits a `UserWarning` on import. - **Transit Least Squares ([TLS](https://ui.adsabs.harvard.edu/abs/2019A%26A...623A..39H/abstract))** (`cuvarbase.tls`) - GPU transit - detection with optimal depth fitting and Ofir (2014) period grids. - The epoch grid is duration-scaled and failed trial periods are masked - out of the SDE/FAP statistics, but the rework has not yet been - validated against the reference `transitleastsquares` package. Light - curves above ~3,500 points exceed the kernel's shared-memory budget - (a `ValueError` is raised). + detection with a limb-darkened template, optimal depth fitting, and + Ofir (2014) period grids. The survey-scale fast path + (`tls_search_batch`, default) folds each light curve once into phase + bins and refines the top candidates exactly, handling **arbitrary + light-curve length** (the legacy per-point kernel is still available + and caps at ~3,500 points). Detection significance now matches both + the reference `transitleastsquares` and the GTLS package to **1–3%** + with 100% injected-transit recovery in our tests (see + [Performance](#transit-least-squares-tls)), but a full + injection-recovery completeness campaign is still outstanding — so it + remains flagged experimental and emits a `UserWarning` on import. - **NUFFT-based Likelihood Ratio Test** (`cuvarbase.nufft_lrt`, contributed by **Jamila Taaki** / [@xiaziyna](https://github.com/xiaziyna)) - @@ -203,23 +221,21 @@ v1.0 is a major modernization of cuvarbase — the first major release since the ### ⚡ Performance Improvements (Major Update) -**Dramatically Faster BLS Transit Detection** — **257-354x faster** than astropy `BoxLeastSquares`, consistent across all 7 GPU architectures tested (V100 through H200): -- Adaptive block sizing automatically selects the CUDA block size from - the dataset size. In the v1.0 release benchmark it measures parity to - ~1.3x over the fixed-block kernel on realistic Keplerian grids (RTX - A5000, Jun 2026; - `benchmarks/results/bls_adaptive_keplerian_benchmark_rtxa5000_jun2026.json`). - Earlier pre-release measurements showed 1.4-5.3x (up to 90x for tiny - lightcurves), but those gains shrank once thread-safe kernel caching - landed and amortized the per-call kernel handling the adaptive path - used to avoid -- Particularly beneficial for ground-based surveys and sparse time series -- Thread-safe kernel caching with LRU eviction for production environments -- **New function**: `eebls_gpu_fast_adaptive()` - drop-in replacement with automatic optimization -- Best cost-efficiency: RTX 4000 Ada at **$0.14 per million lightcurves** -- See [docs/BENCHMARK_RESULTS.md](docs/BENCHMARK_RESULTS.md) for full results across GPUs - -This optimization makes large-scale BLS searches practical and efficient for all-sky surveys. +**Faster BLS transit search** — **257-354x faster** than astropy `BoxLeastSquares`, consistent across all 7 GPU architectures tested (V100 through H200). Relative to the last release (0.2.6), whose BLS *kernel* v1.0 inherits essentially unchanged: + +- **Survey-speed kernels** (fused-noverlap, conflict-scatter, occupancy-aware + chunking) make the per-frequency kernel **2.9-9.2x faster** and end-to-end + survey searches **2.0-12.7x faster** than the pre-optimization v1.0 path +- **Batched multi-lightcurve search** (`eebls_gpu_batch`) is new — 0.2.6 offered + only single-lightcurve calls, which recompiled the kernel on *every* call; + v1.0's LRU kernel cache alone makes a naive per-lightcurve loop **34x faster** +- **Adaptive block sizing** (`eebls_gpu_fast_adaptive()`) auto-tunes the CUDA + block size from the dataset (~1.3x over the fixed-block kernel on realistic + Keplerian grids) +- Best cost-efficiency: RTX 4000 Ada at **$0.14 per million lightcurves**; + see [docs/BENCHMARK_RESULTS.md](docs/BENCHMARK_RESULTS.md) for full results across GPUs + +This makes large-scale BLS searches practical and efficient for all-sky surveys. ### Breaking Changes - **Dropped Python 2.7 support** - now requires Python 3.9+ diff --git a/analysis/GTLS_COMPARISON.md b/analysis/GTLS_COMPARISON.md new file mode 100644 index 0000000..0e20c11 --- /dev/null +++ b/analysis/GTLS_COMPARISON.md @@ -0,0 +1,240 @@ +# cuvarbase vs GTLS — apples-to-apples reproduction of the GTLS Fig. 7 benchmark + +**What this is.** GTLS (Hu, Ge, Jin & Willis, arXiv:2607.00348, submitted 1 Jul 2026) +is the first and only *other* GPU implementation of Transit Least Squares — a CuPy +reimplementation of Hippke & Heller's (2019) TLS (`pip install gputls`, v0.5.1). +Their Fig. 7 reports single-light-curve search time vs light-curve baseline for +GTLS, reference CPU-TLS, and cuvarbase's GPU-BLS. This document reproduces that +figure **on one GPU, holding the search fair**, using our improved TLS +(`feature/tls-fast-survey`) and improved BLS (`feature/bls-survey-speed`). + +**Figure:** `gtls_fig7_reproduction.png` (this directory). Benchmark: `scripts/gtls_benchmark/`. Raw data: `benchmarks/results/gtls_comparison_jul2026/`. + +All measurements: single RTX A5000 (24 GB, sm_86), CUDA 12.x, cupy 13.6, +one injected batman transit per baseline (P=8.13 d, depth=4e-3, 110–400 ppm-class +noise, Keplerian-consistent duration so both grids bracket it), 30-min cadence. +GTLS ran on the *same* A5000 as cuvarbase, so all ratios below are same-hardware. + +--- + +## 1. The fairness protocol (what "apples-to-apples" required) + +The GTLS paper's absolute numbers are on an RTX 4090 (GTLS/BLS) and a Ryzen 7950X +(CPU-TLS). Rather than trust cross-hardware ratios, we run **every method on the +same A5000** and equalize the *search*, not just the hardware. Five knobs had to +be matched (each was a real gap): + +| axis | GTLS | cuvarbase default | how we matched it | +|---|---|---|---| +| **period grid** | Ofir, os=3, Pmax=S/2 | Ofir, os=3 | identical: the *same* array passed to all methods (grids already agreed to 0.05%: 191,837 vs 191,742 at 1500 d) | +| **epoch (T0) density** | `T0_fit_margin` → SKIP_POINT = 8 epochs/duration (default); =0 → every cadence (paper Fig 7) | `t0_oversample`=3 | cuvarbase-matched uses `t0_oversample=8`; GTLS run at both settings | +| **duration grid** | ~36/period over a q-window of ratio ~31 (log-1.1) | 15 over [0.5q,2q] | cuvarbase-matched uses `n_durations=38` and per-period `qmin/qmax` = GTLS's own kernel window | +| **template** | Hippke reference LD (a=23.1, b≈0.32) | LD (a=15, b=0) | left as-is — measured to cost <3% SDE (below) | +| **light curve / SNR** | — | — | one injected transit per baseline, fed to *all* methods → identical SNR by construction | + +Every method's chi²(P) (or BLS power) spectrum is additionally re-scored with **one +identical SDE routine**, so "detection significance" means the same thing for all. + +**On the epoch axis (the crux).** GTLS exposes epoch density through +`T0_fit_margin`: the default 0.125 compiles to `SKIP_POINT=8` = **8 trial epochs +per transit duration** in the coarse SDE scan; `T0_fit_margin=0` scans **every +cadence** (its most expensive O(N²) mode). We measured both. Our A5000 +`gtls_full` numbers (393 s at 1000 d) extrapolate to ~1200 s at 1500 d — 35× the +paper's 33.3 s, implausible even after hardware — whereas `gtls_skip8` (76 s at +1000 d → ~155 s at 1500 d, ≈60 s hardware-adjusted for a 4090) lands within ~2× of +the paper. **So the paper's Fig. 7 used GTLS's *default* (skip=8), not full-scan.** +The true apples-to-apples is therefore **cuvarbase-TLS at `t0_oversample=8` vs +GTLS-skip8** (both = 8 epochs/duration); `gtls_full` is shown only as a "finest +epoch" upper curve. + +--- + +## 2. Results — runtime (per light curve, same A5000) + +Per-light-curve search time, all on the same A5000 (GTLS `full`/`skip8` measured +directly through 1000 d; `skip8` also at the paper's 1500/2000/3000 d anchors; +`full` beyond 1000 d omitted — it reaches ~20 min/point): + +| baseline | GTLS full | **GTLS skip8 (paper cfg)** | **cuv TLS matched** | cuv TLS default | cuv BLS (Kunimoto) | cuv BLS (sensible) | +|---:|---:|---:|---:|---:|---:|---:| +| 200 d | 5.9 s | 4.1 s | **0.138 s** | 0.041 s | 0.538 s | 0.011 s | +| 500 d | 60.2 s | 22.3 s | **0.402 s** | 0.119 s | 1.485 s | 0.032 s | +| 1000 d | 392.6 s| 75.8 s | **0.883 s** | 0.232 s | 3.279 s | 0.101 s | +| 1500 d | (~1200 s*) | 177.9 s | **1.437 s** | 0.409 s | 5.292 s | 0.207 s | +| 2000 d | — | 348.3 s | 2.037 s | 0.627 s | 7.499 s | 0.346 s | +| 3000 d | — | (~830 s*) | 3.460 s | 1.162 s | 12.626 s | 0.730 s | + +\* extrapolated. GTLS scales **super-quadratically** (measured exponent ≈2.5–2.7), +because on a 24 GB GPU long light curves force tiny period batches → thousands of +Python-driven per-batch kernel launches. cuvarbase scales cleanly ~linearly. +(For reference the paper's own 4090 GTLS points are 33.3 s @1500 d and 138 s +@3000 d — i.e. skip=8 on faster hardware.) + +**Speedup, cuvarbase-TLS-matched vs GTLS-skip8 (same A5000, matched 8 +epochs/duration, matched durations & period grid, equal SDE):** + +| baseline | 200 | 500 | 1000 | 1500 | 2000 | +|---|---|---|---|---|---| +| **speedup** | **30×** | **55×** | **86×** | **124×** | **171×** | + +The epoch-matched speedup *grows monotonically* with baseline (GTLS's per-call +recompile + launch overhead compound); cuv-TLS *default* is a further ~3–4× on top, +and vs GTLS-*full* the ratio is 43× → 150× → 445×. + +**Cross-check against the paper's own hardware (immune to the A5000-vs-4090 +question).** Take the paper's *published* GTLS numbers on its RTX 4090 and compare +to cuvarbase on our *slower* A5000: + +| baseline | paper GTLS (RTX 4090) | cuvarbase-TLS-matched (A5000) | cuvarbase wins by | +|---|---|---|---| +| 1500 d | 33.3 s | 1.44 s | **23×** | +| 3000 d | 138 s | 3.46 s | **40×** | + +cuvarbase on the weaker GPU already beats GTLS on the stronger GPU by 23–40× — and +would widen further on matched hardware. (Our *same-GPU* GTLS is ~5× slower than +the paper's 4090 GTLS, more than the ~2× hardware gap: GTLS's runtime is dominated +by per-batch kernel-launch overhead that is very GPU/driver/CuPy-version-sensitive. +We anchor on both the same-GPU ratio and this paper-hardware cross-check so the +conclusion holds either way.) + +**Bonus — improved BLS.** At the paper's *exact* Kunimoto BLS config, our July +`feature/bls-survey-speed` batched BLS runs **5.3 s @1500 d on the A5000 vs the +paper's reported 121.1 s cuvarbase-BLS on a 4090 — ~23× faster on weaker +hardware** (opt1–opt4 + batched kernel; the paper's exact cuvarbase entry point / +version is unspecified). + +## 2b. Single light curve — GTLS's home turf, and the cold-start case + +Every number above is already **single-light-curve** (GTLS has no batch API, so +cuvarbase was timed one LC at a time too — batching would only widen the gap). The +warm speedups assume the kernel JIT is compiled, which amortizes across any real +workload. For the strict **cold single shot** — one star, a fresh process, kernel +compile *included*, and the on-disk pycuda/cupy kernel cache *cleared* before every +run (first-run / fresh-container worst case) — full launch-to-answer wall time on a +second A5000: + +| baseline | cuvarbase-TLS (matched) | GTLS-skip8 | cold ratio | +|---:|---:|---:|---:| +| 200 d | 4.1 s | 10.7 s | **2.6×** | +| 500 d | 4.5 s | 27.8 s | **6.1×** | +| 1000 d | 4.8 s | 83.8 s | **17×** | +| 1500 d | 5.6 s | 191.0 s | **34×** | + +cuvarbase's cold cost is a ~fixed **~3–4 s kernel compile** that barely grows with +baseline (its search is 0.04–1.4 s); GTLS's cost is its *search*, which explodes — +so the ratio grows from 2.6× (both fixed-cost-bound at short baselines) to 34× at +Kepler length. This is the pessimistic floor: from the **2nd star onward** (disk +kernel cache warm) cuvarbase drops to ~0.5–2 s and the ratio snaps back toward the +warm 30–171×, while GTLS recompiles *and* re-searches on every call. SDE parity +holds cold too. (Raw: `benchmarks/results/gtls_comparison_jul2026/cold_single_shot_a5000.txt`; +harness: `scripts/gtls_benchmark/cold_shot.py` + `cold_driver.sh`.) + +## 3. Results — detection significance (SDE parity) + +Scored by the one identical statistic, **every method agrees closely at every +baseline** — GTLS vs cuvarbase-TLS to ~1–3%, and the full 6-method spread (which +includes BLS, whose box template scores marginally higher on this signal) ≤~10%: + +| baseline | SDE: GTLS-skip8 / cuv-TLS-matched | full 6-method spread | +|---:|---|---| +| 200 d | 34.2 / 33.8 (−1%) | 33.4 – 35.2 | +| 500 d | 53.4 / 53.2 (−0.4%) | 53.1 – 56.5 | +| 1000 d | 89.5 / 88.7 (−0.9%) | 86.6 – 93.4 | +| 1500 d | — / 103.5 | 99.9 – 110.9 | +| 3000 d | — / 150.4 | 150.2 – 161.7 | + +100% recovery of the injected period in all cells. So the large speed gaps are +**not** bought with sensitivity — the whole point of the fair comparison. This +independently corroborates the parallel session's finding (commit c4d10ff) that +cuvarbase's coarse fast path sits within 1–3% of *reference CPU-TLS* SDE; here we +see the same ≤3% parity against *GTLS*. + +--- + +## 4. What GTLS does differently from cuvarbase + +Both implement the same TLS math (fold → limb-darkened template → χ² → SDE), and +several high-level strategies match (Ofir period grid; hierarchical coarse-then- +refine T0; a moving-average depth estimate). The differences that matter: + +**GTLS design choices** +- **Single-light-curve, per-call CuPy JIT.** `gtls(t,y).power()` compiles its + CUDA (`cp.RawModule(...).compile()`) on *every* call — no cross-call caching, + no batch API. Fine for one star, costly for a survey. +- **float32 throughout + `(int)` phase fold.** The fold is + `phase = t/P − (int)(t/P)` (truncation, not floor → wrong for t<0 / raw BKJD), + and cumulative sums / residuals accumulate in float32 over up to ~150k points. +- **cumsum moving average** for O(1) in-window depth at any duration; a global + log-1.1 duration grid masked per-period; edge padding + an explicit + edge-effect χ² subtraction for wrap-around transits. +- **Multi-GPU** via `subprocess` per device splitting the period grid (their 79 s + dual-4090 number). Only the coarse scan is parallelized; refinement is 1-GPU. + +**cuvarbase design choices (why it wins)** +- **Batch-native + cached kernels.** One kernel launch over *all* light curves, + one block per (period, LC); LRU-cached compiled kernels. Amortizes launch and + compile — the dominant survey costs. +- **Float-float (t_hi, t_lo) fold**: pure-FP32 FMA fold with 3e-8 phase error at a + 1400-d baseline, vs GTLS's float32/truncation fold (which drifts and mishandles + negative epochs). +- **Fold-once, phase-binned scan** with integrated-template tables (S1=∫T, + S2=∫T²): all durations and epochs come from a single fold, so finer duration + grids are nearly free. This is the same asymptotic trick as GTLS's cumsum but + applied inside a batched, bank-conflict-aware shared-memory kernel. +- **Clean ~linear scaling** in baseline; no period-batch/launch cliff. +- **Exact top-K refinement** kept off the SDE spectrum (SDE from the uniform + coarse grid), so precision is refined without deflating significance. + +Net: cuvarbase and GTLS share the *algorithm*; cuvarbase's *engineering* +(batching, kernel caching, FF fold, single-fold scan) is a generation ahead, and +that shows up as 1–2 orders of magnitude in wall-clock at equal detection. + +--- + +## 5. The BLS comparison — a fairness caveat in the paper + +The GTLS paper concludes "GTLS is 3.6× faster than GPU-BLS" (33.3 s vs 121.1 s at +1500 d). Its BLS is **cuvarbase** run with **Kunimoto et al. (2023, QLP DR notes +003, RNAAS 7:28)** parameters: `qmin=2e-4, qmax=0.15, dlogq=0.1, noverlap=3`. + +That comparison flatters GTLS: +- `qmin=2e-4` searches transit durations down to 0.02% of the period — *sub- + cadence* for 30-min data (~2.9 min at P=10 d). GTLS's own grid also goes that + fine, but its cumsum moving-average makes fine durations O(1); cuvarbase's BLS + kernel re-bins the folded curve into up to `1/qmin = 5000` phase bins per + duration level, so its cost scales with `1/qmin`. Same qmin, wildly different + cost. (Measured: BLS 1.47 s at qmin=2e-4 vs **0.059 s** at qmin=4e-3, 500 d.) +- `noverlap=3` is not a power of two, so it bypasses cuvarbase's fastest *fused* + BLS kernel (opt1) and runs 3 separate phase passes. +- The paper predates our July BLS optimizations (opt1–opt4). + +With a physically sensible BLS config for 30-min data (`qmin=2e-3` ≈ one cadence, +fused `noverlap=2`), cuvarbase-BLS runs **0.01–0.73 s** across 200–3000 d — faster +than TLS (as expected: box < template) and faster than GTLS. So the paper's BLS +result is config- and version-contingent, not fundamental. The clean, meaningful +comparison is **TLS-vs-TLS** (GTLS vs cuvarbase-TLS), where cuvarbase wins outright. + +--- + +## 6. What (if anything) to adopt from GTLS + +- **Multi-GPU scale-out.** The one capability GTLS has that cuvarbase TLS lacks. + Low priority (cuvarbase is already ~100× faster single-GPU and batches many LCs + per launch), but a clean win for the very largest surveys — and easy, since + cuvarbase's batch grid splits trivially across devices. +- **Richer SNR outputs** (GTLS returns snr / snrPink / snrFit / snrFitPink). Nice- + to-have reporting, not performance. +- **Nothing algorithmic.** GTLS's core tricks (Ofir grid, cumsum depth, coarse+ + refine T0) are already present in cuvarbase, generally in a more robust form. + Their float32/truncation fold and per-call recompile are things to *avoid*, not + adopt. + +## 7. Bottom line + +At **matched search space, matched epoch density, and equal SDE**, cuvarbase's TLS +is **tens to >100× faster than GTLS on the same GPU**, and its advantage grows with +baseline because GTLS's per-call recompile and period-batch launch overhead scale +super-quadratically while cuvarbase scales linearly. cuvarbase is also numerically +more robust (FF fold vs float32/int-truncation). The GTLS paper's BLS comparison is +not cost-matched and flatters GTLS; the honest, apples-to-apples story is that +cuvarbase is the faster GPU TLS by a wide, sensitivity-neutral margin. diff --git a/analysis/TLS_COST_ANALYSIS.md b/analysis/TLS_COST_ANALYSIS.md new file mode 100644 index 0000000..e7ba957 --- /dev/null +++ b/analysis/TLS_COST_ANALYSIS.md @@ -0,0 +1,135 @@ +# TLS fidelity, throughput, and cost: cuvarbase vs CPU vs GTLS + +Three questions, answered with measurements (RTX A5000, `scripts/tls_fidelity_experiment.py`, +`scripts/tls_matched_timing.py`, `scripts/benchmark_tls_survey.py`; raw in +`benchmarks/results/tls_survey_jul2026/`): + +1. Is the coarse-epoch-grid + refinement fast path **lossy** — does it sacrifice SNR/SDE? +2. How much **faster** is it, apples-to-apples (same light curves, same grid, same detectability)? +3. Is it **cheaper**, and is it the cheapest TLS available? + +## 0. What the reference "CPU pipeline" is + +The `transitleastsquares` package (Hippke & Heller 2019), pip-installed, called as a +user would: `transitleastsquares(t, y, dy).power(R_star=1, M_star=1, period_min, period_max, +oversampling_factor=3, use_threads=cpu_count())`. It runs on *all* CPU cores. All CPU +timings below are that package on the same machine as the GPU (a RunPod pod), except the +4-year Kepler row (>15 min/LC) which uses the published 522 s figure (16-core Ryzen 9 +7950X, GTLS paper). + +## 1. Fidelity: it is NOT lossy in detectability (measured) + +The detection statistic is the SDE, built from the whole χ²(period) spectrum. cuvarbase's +default fast path scans a **coarse epoch grid** (`t0_oversample=3`, ~3 epochs per transit +duration) plus an exact refinement of the top candidate periods; the reference steps t0 +~100× finer *everywhere*. Does that cost detectability? + +To compare cleanly, the *statistic* is held fixed: cuvarbase and the reference normalize +SR→SDE differently, so SDE is recomputed with `cuvarbase.tls_stats` on **both** methods' +χ² spectra. Only spectrum fidelity then varies. Identical injected light curves, one +shared Ofir period grid. + +| Signal | cuvarbase t0=3 (default) | cuvarbase t0=33 (matched) | reference | recovery | +|---|---:|---:|---:|:--:| +| tess-ffi, depth 0.005 (strong) | SDE 14.5 (**0.99×**) | 15.0 (**1.03×**) | 14.61 | 12/12 all | +| tess-ffi, depth 0.002 (marginal) | 12.01 (**0.97×**) | 12.47 (**1.01×**) | 12.37 | 10/10 all | +| k2, depth 0.004 (narrow, q≈0.014) | 25.23 (**0.98×**) | 26.11 (**1.01×**) | 25.82 | 6/6 all | + +**The default fast path is within 1–3% of the reference SDE, and matched (t0=33) is within +1%.** 100% recovery in every case, including a marginal near-threshold depth and a narrow +transit — the two regimes where any loss would show. + +Why the coarse epoch grid barely moves the SDE: **SDE is a period-space contrast, +`(peak − mean)/std` of the spectrum.** A coarser t0 grid lowers the best-fit quality at +*every* trial period by roughly the same amount, so the normalized contrast between the +true-period peak and the background is preserved. The finer reference grid raises all fits, +again roughly uniformly. The epoch grid mostly sets *reported t0/parameter precision* — and +that is exactly what the exact refinement pass restores. The duration-scaled t0 grid also +guarantees at least one tested epoch overlaps the transit, so even narrow transits don't +fall through. + +The small residual (1–3% at default) is in the **safe direction**: cuvarbase slightly +*under*-reports significance, never over-reports. Refinement is deliberately excluded from +the SDE (it feeds parameters only) precisely so the statistic stays on a uniform-fidelity +spectrum — sharpening only the peak would *inflate* SDE and manufacture false positives. + +Earlier internal notes cited a "~5–15% SDE loss." That was a *cuvarbase-fast-vs-cuvarbase-legacy* +artifact (two of our own kernels), **not** a loss versus the reference. Against the actual +reference package it is parity. + +## 2. Throughput, apples-to-apples + +Matched fidelity (t0=33, SDE parity confirmed above) costs 6–15× over the default coarse +grid: tess-ffi ~6×, k2 ~12×, TESS-yr 14.6×, Kepler-4yr 8.4× (176.8 → 1479 ms/LC on A5000). + +Same light curves, same period grid, single A5000 GPU vs all CPU cores of the same pod: + +| Regime | cuvarbase default | cuvarbase matched (SDE parity) | reference CPU | speedup (matched / default) | +|---|---:|---:|---:|---:| +| tess-ffi (marginal) | 2.6 ms/LC | 13.8 ms/LC | 46,222 ms/LC | 3,300× / 17,500× | +| k2 (narrow) | 5.3 ms/LC | 63.1 ms/LC | 61,445 ms/LC | 970× / 11,600× | + +So **even at genuine SDE parity (matched t0=33), cuvarbase is ~1,000–3,000× faster than the +reference TLS on the same machine**; at the default grid (already SDE-parity for detection) +it is ~11,000–17,000×. Caveat: this pod's reference is unusually slow (46–61 s/LC — a +slower CPU and 96-thread oversubscription on a small problem); a faster CPU narrows the raw +speedup. **Throughput ratio is the market-independent invariant; the exact multiplier is +CPU-dependent.** The robust claim is "thousands of times faster." + +## 3. Cost + +Cost = throughput × ($/hr). The throughput advantage above is measured and market-independent; +the dollar multiplier depends entirely on how you price the two markets, and an earlier +version of this note over-pinned it by comparing a lucky **$0.16/hr spot GPU against a +$2.72/hr AWS on-demand CPU** — two different markets. Corrected inputs: + +- **GPU**: RunPod A5000 list price is **$0.27/hr** (I paid $0.16 on some spot pods and $0.27 + on others — it fluctuates). Use $0.27. +- **CPU**: RunPod does not publish CPU-pod pricing; AWS on-demand 16-vCPU `c6i.4xlarge` is + **$0.68/hr**, 64-vCPU `c6i.16xlarge` is $2.72/hr. Cross-market, so treat as indicative only. + +Cost per million light curves at genuine full fidelity (matched t0=33, A5000 $0.27/hr): + +| Regime | cuvarbase matched | reference CPU | note | +|---|---:|---:|---| +| Kepler-4yr | ~$111/M | ~$98,600/M (16-core, published 522 s) | ~890× cheaper | +| TESS-yr | ~$24/M | (not measured) | — | + +At the default grid (already detection-parity): Kepler ~$13/M, TESS-FFI a few cents/M. But +the honest headline is the **throughput invariant (thousands×)**, not a single dollar ratio; +the ~890× above already uses the *most* CPU-favorable pairing (cheap 16-vCPU CPU, list-price +GPU, full-fidelity GPU). Under any reasonable pricing, GPU TLS is hundreds-to-thousands of +times cheaper. + +## 4. Versus GTLS (the only other GPU TLS) + +[GTLS](https://arxiv.org/abs/2607.00348) (arXiv:2607.00348, Hu, Ge, Jin, Willis, 1 Jul 2026; +CuPy, RTX 4090) reports a 3000-day light curve in **138 s** (single GPU) / 79 s (dual) vs +**3289 s** for CPU TLS → 24× / 42×, at TLS-equivalent detection (matched precision/recall). +A 1500-day case is ~33 s. cuvarbase does the comparable Kepler-4yr configuration in **177 ms/LC +at the default grid** (SDE-parity) or **1.48 s/LC at matched t0=33** on an A5000 (< a 4090): + +| | fidelity | time/LC | vs GTLS 1500-day | +|---|---|---:|---:| +| GTLS (RTX 4090) | TLS-matched | ~33 s | 1× | +| cuvarbase matched (A5000) | SDE parity, matched t0 | 1.48 s | ~22× faster | +| cuvarbase default (A5000) | SDE parity for detection | 0.177 s | ~190× faster | + +cuvarbase wins on hardware-hours (hand-written kernels + phase-binned scan vs CuPy per-point) +and on hardware price (A5000 < 4090), on a fidelity basis GTLS's own detection metric would +call equivalent. + +## Bottom line + +- **Not lossy.** Detection SDE is at parity with the reference (0.97–1.03×) with 100% + recovery, including marginal and narrow transits. The coarse grid trades *epoch/parameter + precision* for speed, and the refinement restores that. Apples-to-apples (matched t0=33) is + within 1% of the reference SDE. +- **Fastest.** ~1,000–3,000× faster than reference CPU TLS at genuine SDE parity on the same + machine; ~22–190× faster than GTLS on cheaper hardware. +- **Cheapest.** Hundreds-to-thousands of times cheaper per light curve than CPU TLS under any + reasonable pricing, and cheaper than GTLS. The exact dollar multiplier is pricing-dependent; + the throughput invariant is not. +- Still **EXPERIMENTAL** pending a full injection–recovery *completeness* campaign across a + (period, depth, ndata) grid (item D3). Three-regime SDE parity is strong evidence, not a + completeness proof. diff --git a/analysis/gtls_fig7_reproduction.png b/analysis/gtls_fig7_reproduction.png new file mode 100644 index 0000000..e7a6115 Binary files /dev/null and b/analysis/gtls_fig7_reproduction.png differ diff --git a/benchmarks/results/gtls_comparison_jul2026/cold_single_shot_a5000.txt b/benchmarks/results/gtls_comparison_jul2026/cold_single_shot_a5000.txt new file mode 100644 index 0000000..fb566b4 --- /dev/null +++ b/benchmarks/results/gtls_comparison_jul2026/cold_single_shot_a5000.txt @@ -0,0 +1,24 @@ +Cold single-shot: one light curve, fresh process, NO in-process warmup, on-disk +pycuda/cupy kernel cache CLEARED before each run (true first-run / fresh-container +case). NVIDIA RTX A5000, 7 Jul 2026. Injected transit P=8.13d depth=4e-3. +full_wall_s = python import + CUDA context init + JIT compile + search +search_compile = compile + search only (context pre-initialized) + +method baseline full_wall_s search_compile nper SDE +cuv_tls_default 200 4.27 2.826 23057 33.48 +cuv_tls_matched 200 4.10 2.852 23057 34.12 +gtls_skip8 200 10.69 8.402 23057 34.41 +cuv_tls_default 500 4.75 3.620 61017 57.59 +cuv_tls_matched 500 4.52 3.226 61017 57.09 +gtls_skip8 500 27.79 25.730 61017 58.53 +cuv_tls_default 1000 5.58 4.346 125932 85.35 +cuv_tls_matched 1000 4.81 3.668 125932 85.79 +gtls_skip8 1000 83.75 81.607 125932 87.28 +cuv_tls_default 1500 5.83 4.612 191742 102.07 +cuv_tls_matched 1500 5.59 4.264 191742 104.03 +gtls_skip8 1500 191.00 188.714 191742 106.91 + +Cold ratio (full_wall, cuv_tls_matched vs gtls_skip8): 2.6x / 6.1x / 17x / 34x +Grows because cuvarbase's cost is a ~fixed ~3-4s compile while GTLS's is its +exploding search. 2nd star onward (disk cache warm): cuvarbase ~0.5-2s -> ratio +snaps back toward the warm 30-171x. GTLS recompiles+re-searches every call. diff --git a/benchmarks/results/gtls_comparison_jul2026/results_cuv.json b/benchmarks/results/gtls_comparison_jul2026/results_cuv.json new file mode 100644 index 0000000..8970897 --- /dev/null +++ b/benchmarks/results/gtls_comparison_jul2026/results_cuv.json @@ -0,0 +1,667 @@ +{ + "script": "gtls_apples_bench.py", + "timestamp": "2026-07-06T20:24:53", + "inj": { + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "u": [ + 0.4804, + 0.1867 + ], + "cadence_days": 0.020833333333333332 + }, + "match_template": false, + "baselines": [ + 200, + 500, + 1000, + 1500, + 2000, + 3000 + ], + "results": { + "200": { + "meta": { + "ndata": 9600, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 200, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 13.653358801550656 + }, + "nperiods": 23057, + "n_dur_matched": 38, + "methods": { + "cuv_tls_matched": { + "method": "cuv_tls_matched", + "time_s": 0.13755610957741737, + "batch_time_s": 0.13755610957741737, + "times_s": [ + 0.14206748269498348, + 0.13755610957741737, + 0.13514303229749203 + ], + "n_lcs": 1, + "t0_oversample": 8.0, + "n_durations": 38, + "period_native": 8.130030632019043, + "sde_native": 33.59562901812796, + "sde_identical": 33.75055979295671, + "best_period_identical": 8.130030632019043, + "depth_snr": 15.89531655761043, + "recovered": true, + "recovered_native": true, + "n_periods": 23057 + }, + "cuv_tls_default": { + "method": "cuv_tls_default", + "time_s": 0.04108639247715473, + "batch_time_s": 0.04108639247715473, + "times_s": [ + 0.04108639247715473, + 0.0410964023321867, + 0.040234677493572235 + ], + "n_lcs": 1, + "t0_oversample": 3.0, + "n_durations": 15, + "period_native": 8.130030632019043, + "sde_native": 33.292362285426535, + "sde_identical": 33.44892897086804, + "best_period_identical": 8.130030632019043, + "depth_snr": 15.484280367503382, + "recovered": true, + "recovered_native": true, + "n_periods": 23057 + }, + "cuv_bls_kunimoto": { + "method": "cuv_bls_kunimoto", + "cfg": "kunimoto", + "time_s": 0.5383373517543077, + "batch_time_s": 0.5383373517543077, + "times_s": [ + 0.5379391890019178, + 0.538496345281601, + 0.5383373517543077 + ], + "n_lcs": 1, + "n_periods": 23057, + "sde_identical": 35.2025799976132, + "best_period_identical": 8.13003035214252, + "recovered": true, + "qcfg": { + "qmin": 0.0002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 3 + } + }, + "cuv_bls_matched": { + "method": "cuv_bls_matched", + "cfg": "matched", + "time_s": 0.010561700910329819, + "batch_time_s": 0.010561700910329819, + "times_s": [ + 0.010561700910329819, + 0.011295026168227196, + 0.010273467749357224 + ], + "n_lcs": 1, + "n_periods": 23057, + "sde_identical": 34.70987328513982, + "best_period_identical": 8.13003035214252, + "recovered": true, + "qcfg": { + "qmin": 0.002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 2 + } + } + } + }, + "500": { + "meta": { + "ndata": 24000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 500, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 21.767011164065 + }, + "nperiods": 61017, + "n_dur_matched": 38, + "methods": { + "cuv_tls_matched": { + "method": "cuv_tls_matched", + "time_s": 0.40233735367655754, + "batch_time_s": 0.40233735367655754, + "times_s": [ + 0.4016232769936323, + 0.4110007472336292, + 0.40233735367655754 + ], + "n_lcs": 1, + "t0_oversample": 8.0, + "n_durations": 38, + "period_native": 8.130175590515137, + "sde_native": 53.01878151851455, + "sde_identical": 53.14530587775627, + "best_period_identical": 8.130175590515137, + "depth_snr": 22.741917673107043, + "recovered": true, + "recovered_native": true, + "n_periods": 61017 + }, + "cuv_tls_default": { + "method": "cuv_tls_default", + "time_s": 0.11858376115560532, + "batch_time_s": 0.11858376115560532, + "times_s": [ + 0.11858376115560532, + 0.11885972693562508, + 0.11000512167811394 + ], + "n_lcs": 1, + "t0_oversample": 3.0, + "n_durations": 15, + "period_native": 8.130175590515137, + "sde_native": 53.26162239029376, + "sde_identical": 53.38806041519828, + "best_period_identical": 8.129351615905762, + "depth_snr": 22.191700304067716, + "recovered": true, + "recovered_native": true, + "n_periods": 61017 + }, + "cuv_bls_kunimoto": { + "method": "cuv_bls_kunimoto", + "cfg": "kunimoto", + "time_s": 1.4846770018339157, + "batch_time_s": 1.4846770018339157, + "times_s": [ + 1.4818594921380281, + 1.4846770018339157, + 1.4850654806941748 + ], + "n_lcs": 1, + "n_periods": 61017, + "sde_identical": 56.52696500954521, + "best_period_identical": 8.130175631606068, + "recovered": true, + "qcfg": { + "qmin": 0.0002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 3 + } + }, + "cuv_bls_matched": { + "method": "cuv_bls_matched", + "cfg": "matched", + "time_s": 0.03246651217341423, + "batch_time_s": 0.03246651217341423, + "times_s": [ + 0.03197992965579033, + 0.03349187970161438, + 0.03246651217341423 + ], + "n_lcs": 1, + "n_periods": 61017, + "sde_identical": 55.77652871561681, + "best_period_identical": 8.130175631606068, + "recovered": true, + "qcfg": { + "qmin": 0.002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 2 + } + } + } + }, + "1000": { + "meta": { + "ndata": 48000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 1000, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 30.909105594304876 + }, + "nperiods": 125932, + "n_dur_matched": 38, + "methods": { + "cuv_tls_matched": { + "method": "cuv_tls_matched", + "time_s": 0.8827326986938715, + "batch_time_s": 0.8827326986938715, + "times_s": [ + 0.881113650277257, + 0.8827326986938715, + 0.8842885997146368 + ], + "n_lcs": 1, + "t0_oversample": 8.0, + "n_durations": 38, + "period_native": 8.129958152770996, + "sde_native": 88.61718125069527, + "sde_identical": 88.71963989110473, + "best_period_identical": 8.129958152770996, + "depth_snr": 31.712350389535917, + "recovered": true, + "recovered_native": true, + "n_periods": 125932 + }, + "cuv_tls_default": { + "method": "cuv_tls_default", + "time_s": 0.23190558142960072, + "batch_time_s": 0.23190558142960072, + "times_s": [ + 0.23190558142960072, + 0.24890235997736454, + 0.2289747204631567 + ], + "n_lcs": 1, + "t0_oversample": 3.0, + "n_durations": 15, + "period_native": 8.129958152770996, + "sde_native": 86.52490525299153, + "sde_identical": 86.62860999090962, + "best_period_identical": 8.130370140075684, + "depth_snr": 30.684333707845962, + "recovered": true, + "recovered_native": true, + "n_periods": 125932 + }, + "cuv_bls_kunimoto": { + "method": "cuv_bls_kunimoto", + "cfg": "kunimoto", + "time_s": 3.2789248321205378, + "batch_time_s": 3.2789248321205378, + "times_s": [ + 3.278851928189397, + 3.2854464910924435, + 3.2789248321205378 + ], + "n_lcs": 1, + "n_periods": 125932, + "sde_identical": 93.42207706283025, + "best_period_identical": 8.129958453040548, + "recovered": true, + "qcfg": { + "qmin": 0.0002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 3 + } + }, + "cuv_bls_matched": { + "method": "cuv_bls_matched", + "cfg": "matched", + "time_s": 0.10147341340780258, + "batch_time_s": 0.10147341340780258, + "times_s": [ + 0.10238155163824558, + 0.10147341340780258, + 0.10146233811974525 + ], + "n_lcs": 1, + "n_periods": 125932, + "sde_identical": 92.4722290623255, + "best_period_identical": 8.129958453040548, + "recovered": true, + "qcfg": { + "qmin": 0.002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 2 + } + } + } + }, + "1500": { + "meta": { + "ndata": 72000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 1500, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 37.804438676647734 + }, + "nperiods": 191742, + "n_dur_matched": 38, + "methods": { + "cuv_tls_matched": { + "method": "cuv_tls_matched", + "time_s": 1.4373753536492586, + "batch_time_s": 1.4373753536492586, + "times_s": [ + 1.4392143823206425, + 1.4373753536492586, + 1.43576823733747 + ], + "n_lcs": 1, + "t0_oversample": 8.0, + "n_durations": 38, + "period_native": 8.130034446716309, + "sde_native": 103.42288798192644, + "sde_identical": 103.51420005935486, + "best_period_identical": 8.130034446716309, + "depth_snr": 40.07062782524991, + "recovered": true, + "recovered_native": true, + "n_periods": 191742 + }, + "cuv_tls_default": { + "method": "cuv_tls_default", + "time_s": 0.40924578718841076, + "batch_time_s": 0.40924578718841076, + "times_s": [ + 0.4187461659312248, + 0.40924578718841076, + 0.4073683172464371 + ], + "n_lcs": 1, + "t0_oversample": 3.0, + "n_durations": 15, + "period_native": 8.130034446716309, + "sde_native": 99.8471592139927, + "sde_identical": 99.93955063884552, + "best_period_identical": 8.130034446716309, + "depth_snr": 38.40967211209207, + "recovered": true, + "recovered_native": true, + "n_periods": 191742 + }, + "cuv_bls_kunimoto": { + "method": "cuv_bls_kunimoto", + "cfg": "kunimoto", + "time_s": 5.291578171774745, + "batch_time_s": 5.291578171774745, + "times_s": [ + 5.279095048084855, + 5.291578171774745, + 5.304737301543355 + ], + "n_lcs": 1, + "n_periods": 191742, + "sde_identical": 107.46817842744791, + "best_period_identical": 8.13003429185609, + "recovered": true, + "qcfg": { + "qmin": 0.0002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 3 + } + }, + "cuv_bls_matched": { + "method": "cuv_bls_matched", + "cfg": "matched", + "time_s": 0.20667587965726852, + "batch_time_s": 0.20667587965726852, + "times_s": [ + 0.20533782057464123, + 0.20667587965726852, + 0.20865457504987717 + ], + "n_lcs": 1, + "n_periods": 191742, + "sde_identical": 110.94920831744149, + "best_period_identical": 8.13003429185609, + "recovered": true, + "qcfg": { + "qmin": 0.002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 2 + } + } + } + }, + "2000": { + "meta": { + "ndata": 96000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 2000, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 43.712076332288056 + }, + "nperiods": 258051, + "n_dur_matched": 38, + "methods": { + "cuv_tls_matched": { + "method": "cuv_tls_matched", + "time_s": 2.0367227513343096, + "batch_time_s": 2.0367227513343096, + "times_s": [ + 2.063674498349428, + 2.0367227513343096, + 2.035205539315939 + ], + "n_lcs": 1, + "t0_oversample": 8.0, + "n_durations": 38, + "period_native": 8.130036354064941, + "sde_native": 117.45164141534184, + "sde_identical": 117.53842896522384, + "best_period_identical": 8.130036354064941, + "depth_snr": 44.88384804589285, + "recovered": true, + "recovered_native": true, + "n_periods": 258051 + }, + "cuv_tls_default": { + "method": "cuv_tls_default", + "time_s": 0.6267105527222157, + "batch_time_s": 0.6267105527222157, + "times_s": [ + 0.6267105527222157, + 0.6304767020046711, + 0.6124172136187553 + ], + "n_lcs": 1, + "t0_oversample": 3.0, + "n_durations": 15, + "period_native": 8.130036354064941, + "sde_native": 116.67198138296588, + "sde_identical": 116.75982396228854, + "best_period_identical": 8.129830360412598, + "depth_snr": 43.67934833927807, + "recovered": true, + "recovered_native": true, + "n_periods": 258051 + }, + "cuv_bls_kunimoto": { + "method": "cuv_bls_kunimoto", + "cfg": "kunimoto", + "time_s": 7.498604532331228, + "batch_time_s": 7.498604532331228, + "times_s": [ + 7.498385973274708, + 7.498604532331228, + 7.510715387761593 + ], + "n_lcs": 1, + "n_periods": 258051, + "sde_identical": 127.21260712267089, + "best_period_identical": 8.130036261714308, + "recovered": true, + "qcfg": { + "qmin": 0.0002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 3 + } + }, + "cuv_bls_matched": { + "method": "cuv_bls_matched", + "cfg": "matched", + "time_s": 0.34627664647996426, + "batch_time_s": 0.34627664647996426, + "times_s": [ + 0.35058100521564484, + 0.34386174753308296, + 0.34627664647996426 + ], + "n_lcs": 1, + "n_periods": 258051, + "sde_identical": 127.25345502897856, + "best_period_identical": 8.130036261714308, + "recovered": true, + "qcfg": { + "qmin": 0.002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 2 + } + } + } + }, + "3000": { + "meta": { + "ndata": 144000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 3000, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 53.53614130584746 + }, + "nperiods": 391590, + "n_dur_matched": 38, + "methods": { + "cuv_tls_matched": { + "method": "cuv_tls_matched", + "time_s": 3.459543852135539, + "batch_time_s": 3.459543852135539, + "times_s": [ + 3.459543852135539, + 3.461102804169059, + 3.4592786859720945 + ], + "n_lcs": 1, + "t0_oversample": 8.0, + "n_durations": 38, + "period_native": 8.130058288574219, + "sde_native": 150.27533983989235, + "sde_identical": 150.35053699759433, + "best_period_identical": 8.130058288574219, + "depth_snr": 56.2134288328531, + "recovered": true, + "recovered_native": true, + "n_periods": 391590 + }, + "cuv_tls_default": { + "method": "cuv_tls_default", + "time_s": 1.1623164396733046, + "batch_time_s": 1.1623164396733046, + "times_s": [ + 1.1623164396733046, + 1.1622154470533133, + 1.2753417380154133 + ], + "n_lcs": 1, + "t0_oversample": 3.0, + "n_durations": 15, + "period_native": 8.130058288574219, + "sde_native": 150.15194994799836, + "sde_identical": 150.2269788947036, + "best_period_identical": 8.129920959472656, + "depth_snr": 54.83777535001808, + "recovered": true, + "recovered_native": true, + "n_periods": 391590 + }, + "cuv_bls_kunimoto": { + "method": "cuv_bls_kunimoto", + "cfg": "kunimoto", + "time_s": 12.626147827133536, + "batch_time_s": 12.626147827133536, + "times_s": [ + 12.612651254981756, + 12.626147827133536, + 12.632280489429832 + ], + "n_lcs": 1, + "n_periods": 391590, + "sde_identical": 158.65902805502566, + "best_period_identical": 8.130058422685028, + "recovered": true, + "qcfg": { + "qmin": 0.0002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 3 + } + }, + "cuv_bls_matched": { + "method": "cuv_bls_matched", + "cfg": "matched", + "time_s": 0.7296613436192274, + "batch_time_s": 0.7296613436192274, + "times_s": [ + 0.7476502638310194, + 0.7272099461406469, + 0.7296613436192274 + ], + "n_lcs": 1, + "n_periods": 391590, + "sde_identical": 161.72125764714372, + "best_period_identical": 8.130058422685028, + "recovered": true, + "qcfg": { + "qmin": 0.002, + "qmax": 0.15, + "dlogq": 0.1, + "noverlap": 2 + } + } + } + } + }, + "env": { + "python": "3.11.10", + "numpy": "1.26.4", + "host": "d26a19997861", + "cupy": "13.6.0", + "gpu": "NVIDIA RTX A5000", + "cc": "86", + "gpu_mem_GB": 25.3, + "gputls": "?", + "cuvarbase": "?", + "batman": "2.5.1" + } +} \ No newline at end of file diff --git a/benchmarks/results/gtls_comparison_jul2026/results_gtls.json b/benchmarks/results/gtls_comparison_jul2026/results_gtls.json new file mode 100644 index 0000000..b94a572 --- /dev/null +++ b/benchmarks/results/gtls_comparison_jul2026/results_gtls.json @@ -0,0 +1,194 @@ +{ + "script": "gtls_apples_bench.py", + "timestamp": "2026-07-06T20:28:31", + "inj": { + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "u": [ + 0.4804, + 0.1867 + ], + "cadence_days": 0.020833333333333332 + }, + "match_template": false, + "baselines": [ + 200, + 500, + 1000, + 1500 + ], + "results": { + "200": { + "meta": { + "ndata": 9600, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 200, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 13.653358801550656 + }, + "nperiods": 23057, + "n_dur_matched": 38, + "methods": { + "gtls_full": { + "method": "gtls", + "t0_fit_margin": 0.0, + "time_s": 5.91833676956594, + "times_s": [ + 5.91833676956594 + ], + "compile_s": 0.8467772686854005, + "search_s": 5.071559500880539, + "period_native": 8.130030176386265, + "sde_native": 34.570831298828125, + "sde_identical": 34.12735534425686, + "best_period_identical": 8.130030176386265, + "depth_snr": 0.064205851315256, + "recovered": true, + "recovered_native": true, + "n_periods": 23057, + "n_durations": 52 + }, + "gtls_skip8": { + "method": "gtls", + "t0_fit_margin": 0.125, + "time_s": 4.130032569169998, + "times_s": [ + 4.130032569169998 + ], + "compile_s": 0.6914869425818324, + "search_s": 3.4385456265881658, + "period_native": 8.130030176386265, + "sde_native": 34.657554626464844, + "sde_identical": 34.21832717591669, + "best_period_identical": 8.130030176386265, + "depth_snr": 0.06429166510831873, + "recovered": true, + "recovered_native": true, + "n_periods": 23057, + "n_durations": 52 + } + } + }, + "500": { + "meta": { + "ndata": 24000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 500, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 21.767011164065 + }, + "nperiods": 61017, + "n_dur_matched": 38, + "methods": { + "gtls_full": { + "method": "gtls", + "t0_fit_margin": 0.0, + "time_s": 60.17078699544072, + "times_s": [ + 60.17078699544072 + ], + "compile_s": 1.1312147621065378, + "search_s": 59.039572233334184, + "period_native": 8.130175785064758, + "sde_native": 53.85988235473633, + "sde_identical": 53.24109400906245, + "best_period_identical": 8.130175785064758, + "depth_snr": 0.09136765145994989, + "recovered": true, + "recovered_native": true, + "n_periods": 61017, + "n_durations": 58 + }, + "gtls_skip8": { + "method": "gtls", + "t0_fit_margin": 0.125, + "time_s": 22.259925242513418, + "times_s": [ + 22.259925242513418 + ], + "compile_s": 1.3329955143854022, + "search_s": 20.926929728128016, + "period_native": 8.130175785064758, + "sde_native": 54.02534866333008, + "sde_identical": 53.40667252573126, + "best_period_identical": 8.130175785064758, + "depth_snr": 0.09142911576104762, + "recovered": true, + "recovered_native": true, + "n_periods": 61017, + "n_durations": 58 + } + } + }, + "1000": { + "meta": { + "ndata": 48000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 1000, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 30.909105594304876 + }, + "nperiods": 125932, + "n_dur_matched": 38, + "methods": { + "gtls_full": { + "method": "gtls", + "t0_fit_margin": 0.0, + "time_s": 392.6445415560156, + "times_s": [ + 392.6445415560156 + ], + "compile_s": 2.5499397944658995, + "search_s": 390.0946017615497, + "period_native": 8.12995822670441, + "sde_native": 90.32481384277344, + "sde_identical": 89.23306877100191, + "best_period_identical": 8.12995822670441, + "depth_snr": 0.12784462932992, + "recovered": true, + "recovered_native": true, + "n_periods": 125932, + "n_durations": 63 + }, + "gtls_skip8": { + "method": "gtls", + "t0_fit_margin": 0.125, + "time_s": 75.80983891524374, + "times_s": [ + 75.80983891524374 + ], + "compile_s": 3.2179553182795644, + "search_s": 72.59188359696418, + "period_native": 8.12995822670441, + "sde_native": 90.60254669189453, + "sde_identical": 89.51449068514454, + "best_period_identical": 8.12995822670441, + "depth_snr": 0.12784742666257284, + "recovered": true, + "recovered_native": true, + "n_periods": 125932, + "n_durations": 63 + } + } + } + } +} \ No newline at end of file diff --git a/benchmarks/results/gtls_comparison_jul2026/results_gtls_skip8_big.json b/benchmarks/results/gtls_comparison_jul2026/results_gtls_skip8_big.json new file mode 100644 index 0000000..63b9787 --- /dev/null +++ b/benchmarks/results/gtls_comparison_jul2026/results_gtls_skip8_big.json @@ -0,0 +1,98 @@ +{ + "script": "gtls_apples_bench.py", + "timestamp": "2026-07-06T20:59:05", + "inj": { + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "u": [ + 0.4804, + 0.1867 + ], + "cadence_days": 0.020833333333333332 + }, + "match_template": false, + "baselines": [ + 1500, + 2000, + 3000 + ], + "results": { + "1500": { + "meta": { + "ndata": 72000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 1500, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 37.804438676647734 + }, + "nperiods": 191742, + "n_dur_matched": 38, + "methods": { + "gtls_skip8": { + "method": "gtls", + "t0_fit_margin": 0.125, + "time_s": 177.87423043884337, + "times_s": [ + 177.87423043884337 + ], + "compile_s": 3.721640777774155, + "search_s": 174.15258966106921, + "period_native": 8.130034279159807, + "sde_native": 105.51361083984375, + "sde_identical": 104.18246598078773, + "best_period_identical": 8.130034279159807, + "depth_snr": 0.16124744383685868, + "recovered": true, + "recovered_native": true, + "n_periods": 191742, + "n_durations": 66 + } + } + }, + "2000": { + "meta": { + "ndata": 96000, + "period": 8.13, + "depth": 0.004, + "noise": 0.004, + "baseline": 2000, + "cadence": 0.020833333333333332, + "t0": 2.8455, + "a_over_Rstar": 17.01495360210589, + "T14_days": 0.1618178876422576, + "q_true": 0.019903799217989862, + "snr": 43.712076332288056 + }, + "nperiods": 258051, + "n_dur_matched": 38, + "methods": { + "gtls_skip8": { + "method": "gtls", + "t0_fit_margin": 0.125, + "time_s": 348.3279370646924, + "times_s": [ + 348.3279370646924 + ], + "compile_s": 4.988396569155157, + "search_s": 343.3395404955372, + "period_native": 8.130036228065206, + "sde_native": 120.33523559570312, + "sde_identical": 118.84809423734643, + "best_period_identical": 8.130036228065206, + "depth_snr": 0.18092451137905285, + "recovered": true, + "recovered_native": true, + "n_periods": 258051, + "n_durations": 68 + } + } + } + } +} \ No newline at end of file diff --git a/benchmarks/results/tls_survey_jul2026/fidelity_raw_a5000.txt b/benchmarks/results/tls_survey_jul2026/fidelity_raw_a5000.txt new file mode 100644 index 0000000..424ccc0 --- /dev/null +++ b/benchmarks/results/tls_survey_jul2026/fidelity_raw_a5000.txt @@ -0,0 +1,22 @@ +# TLS fidelity experiment raw output (A5000, 2026-07-06) +## strong signal (tess-ffi depth=0.005) + reference transitleastsquares SDE(identical)= 14.61 SDE(native)= 17.71 depthSNR= 0.03 recov=12/12 39077.1 ms/LC + cuvarbase t0os=3 (default) SDE ratio=0.99 depthSNR ratio=1000.85 speedup=17351x + cuvarbase t0os=33 (matched) SDE ratio=1.03 depthSNR ratio=1002.64 speedup=2914x +## marginal + narrow stress +########## MARGINAL depth=0.002 (near threshold), tess-ffi ########## +=== tess-ffi: ndata=1310 nperiods=2486 P_inj=7.70d depth=0.0020 (10 inj LCs) === + SDE(identical) = cuvarbase SDE recomputed on each method's chi2 spectrum; + cuvarbase t0os=3 (default) SDE(identical)= 12.01 SDE(native)= 12.01 depthSNR= 9.66 recov=10/10 2.6 ms/LC + cuvarbase t0os=33 (matched) SDE(identical)= 12.47 SDE(native)= 12.47 depthSNR= 9.75 recov=10/10 13.8 ms/LC + reference transitleastsquares SDE(identical)= 12.37 SDE(native)= 12.91 depthSNR= 0.01 recov=10/10 46222.2 ms/LC + cuvarbase t0os=3 (default) SDE ratio=0.97 depthSNR ratio=996.36 speedup=17475x + cuvarbase t0os=33 (matched) SDE ratio=1.01 depthSNR ratio=1006.34 speedup=3349x +########## NARROW transit, k2 (q~0.014) ########## +=== k2: ndata=4320 nperiods=9672 P_inj=12.40d depth=0.0040 (6 inj LCs) === + SDE(identical) = cuvarbase SDE recomputed on each method's chi2 spectrum; + cuvarbase t0os=3 (default) SDE(identical)= 25.23 SDE(native)= 25.23 depthSNR=37.74 recov=6/6 5.3 ms/LC + cuvarbase t0os=33 (matched) SDE(identical)= 26.11 SDE(native)= 26.11 depthSNR=37.92 recov=6/6 63.1 ms/LC + reference transitleastsquares SDE(identical)= 25.82 SDE(native)= 29.97 depthSNR= 0.03 recov=6/6 61444.9 ms/LC + cuvarbase t0os=3 (default) SDE ratio=0.98 depthSNR ratio=1236.37 speedup=11578x + cuvarbase t0os=33 (matched) SDE ratio=1.01 depthSNR ratio=1242.21 speedup=974x diff --git a/benchmarks/results/tls_survey_jul2026/tls_survey_a5000.json b/benchmarks/results/tls_survey_jul2026/tls_survey_a5000.json new file mode 100644 index 0000000..6df9fe4 --- /dev/null +++ b/benchmarks/results/tls_survey_jul2026/tls_survey_a5000.json @@ -0,0 +1,2464 @@ +{ + "script": "benchmark_tls_survey.py", + "timestamp": "2026-07-06T17:37:04", + "args": { + "regimes": "tess-ffi,k2,tess-2min,tess-yr,kepler-4yr", + "nlc": null, + "impls": "new,old,reference", + "ref_nlc": 1, + "old_nlc": 5, + "n_iter": 1, + "output": "tls_survey_a5000.json", + "quick": false, + "ref_all": false + }, + "regimes": { + "tess-ffi": { + "config": { + "ndata": 1310, + "baseline": 27.4, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 7.7, + "inject_depth": 0.005, + "period_min": 0.6, + "period_max": 13.7, + "nlc": 100 + }, + "nlc": 100, + "nperiods": 2486, + "impls": { + "new": { + "nlc": 100, + "total_s": 0.46537021710537374, + "times_s": [ + 0.46537021710537374 + ], + "ms_per_lc": 4.653702171053737, + "lc_per_s": 214.88268119521067, + "n_injected": 50, + "n_recovered": 50, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.194946765899658, + "median_sde_noise": 5.454893112182617, + "per_lc": [ + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005532100331038237, + "SDE": 14.04796028137207, + "chi2_min": 1336.756591796875 + }, + { + "injected": false, + "period": 0.6225233674049377, + "T0": 0.542300333010111, + "duration": 0.037806544452905655, + "depth": 0.0005694815190508962, + "SDE": 4.8387885093688965, + "chi2_min": 1315.3824462890625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0050460100173950195, + "SDE": 14.31605339050293, + "chi2_min": 1393.1041259765625 + }, + { + "injected": false, + "period": 2.0671958923339844, + "T0": 1.240600977982922, + "duration": 0.04742983356118202, + "depth": 0.001077972468920052, + "SDE": 5.3955254554748535, + "chi2_min": 1313.3258056640625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005532099865376949, + "SDE": 13.555395126342773, + "chi2_min": 1225.93603515625 + }, + { + "injected": false, + "period": 6.83004903793335, + "T0": 3.3232153407358425, + "duration": 0.14845600724220276, + "depth": 0.0010422980412840843, + "SDE": 5.729757308959961, + "chi2_min": 1240.1666259765625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005443216301500797, + "SDE": 14.323617935180664, + "chi2_min": 1269.003173828125 + }, + { + "injected": false, + "period": 1.3832758665084839, + "T0": 1.2062232874457806, + "duration": 0.0404709056019783, + "depth": 0.0010051717981696129, + "SDE": 6.807766437530518, + "chi2_min": 1265.138427734375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005494272336363792, + "SDE": 14.132584571838379, + "chi2_min": 1249.695068359375 + }, + { + "injected": false, + "period": 9.259944915771484, + "T0": 5.364545925151106, + "duration": 0.1282770186662674, + "depth": 0.0013460032641887665, + "SDE": 4.305014610290527, + "chi2_min": 1306.898681640625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005376006942242384, + "SDE": 13.244661331176758, + "chi2_min": 1383.9041748046875 + }, + { + "injected": false, + "period": 3.789888858795166, + "T0": 2.661259939658663, + "duration": 0.06252489984035492, + "depth": 0.001284691970795393, + "SDE": 6.250540256500244, + "chi2_min": 1278.526123046875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005833100527524948, + "SDE": 14.197710990905762, + "chi2_min": 1307.3194580078125 + }, + { + "injected": false, + "period": 0.694443941116333, + "T0": 0.5433730154117882, + "duration": 0.03825102746486664, + "depth": 0.0007502393564209342, + "SDE": 5.395812034606934, + "chi2_min": 1375.8001708984375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005461629945784807, + "SDE": 14.322482109069824, + "chi2_min": 1400.463134765625 + }, + { + "injected": false, + "period": 0.9697667956352234, + "T0": 0.6234215032222714, + "duration": 0.04170956835150719, + "depth": 0.0007615161594003439, + "SDE": 5.9738569259643555, + "chi2_min": 1345.572998046875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005138101056218147, + "SDE": 14.855719566345215, + "chi2_min": 1374.564697265625 + }, + { + "injected": false, + "period": 8.122530937194824, + "T0": 7.832263005316975, + "duration": 0.08061356842517853, + "depth": 0.0015345076099038124, + "SDE": 5.285528182983398, + "chi2_min": 1408.313232421875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005546604748815298, + "SDE": 14.231895446777344, + "chi2_min": 1320.038330078125 + }, + { + "injected": false, + "period": 6.6303558349609375, + "T0": 1.8257501173602577, + "duration": 0.09650145471096039, + "depth": 0.0013269076589494944, + "SDE": 6.51860237121582, + "chi2_min": 1293.273681640625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005588605999946594, + "SDE": 14.391213417053223, + "chi2_min": 1236.130126953125 + }, + { + "injected": false, + "period": 3.265150547027588, + "T0": 1.6735373315951279, + "duration": 0.0594947412610054, + "depth": 0.0011398136848583817, + "SDE": 4.954017162322998, + "chi2_min": 1306.6485595703125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005358254071325064, + "SDE": 14.025896072387695, + "chi2_min": 1378.85791015625 + }, + { + "injected": false, + "period": 0.9069516062736511, + "T0": 0.4873173068018559, + "duration": 0.041811149567365646, + "depth": 0.0007045392994768918, + "SDE": 7.13300895690918, + "chi2_min": 1326.76806640625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005511259660124779, + "SDE": 14.469883918762207, + "chi2_min": 1315.769775390625 + }, + { + "injected": false, + "period": 6.818082332611084, + "T0": 0.19493036610213732, + "duration": 0.06887488067150116, + "depth": 0.0014663777546957135, + "SDE": 4.655307292938232, + "chi2_min": 1332.3330078125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005003536585718393, + "SDE": 14.677703857421875, + "chi2_min": 1274.4622802734375 + }, + { + "injected": false, + "period": 1.3818519115447998, + "T0": 0.3538014247310741, + "duration": 0.040457021445035934, + "depth": 0.0008182454621419311, + "SDE": 5.503757476806641, + "chi2_min": 1271.795166015625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005669722333550453, + "SDE": 15.375238418579102, + "chi2_min": 1376.2421875 + }, + { + "injected": false, + "period": 9.743551254272461, + "T0": 5.753463031568231, + "duration": 0.09000206738710403, + "depth": 0.0015667061088606715, + "SDE": 5.434820652008057, + "chi2_min": 1213.2532958984375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.1792505532503128, + "depth": 0.005271698348224163, + "SDE": 14.827378273010254, + "chi2_min": 1277.588134765625 + }, + { + "injected": false, + "period": 3.751904010772705, + "T0": 3.4951949631796992, + "duration": 0.05644047260284424, + "depth": 0.0012609886471182108, + "SDE": 4.813412189483643, + "chi2_min": 1313.6197509765625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.1792505532503128, + "depth": 0.0049079651944339275, + "SDE": 14.521245002746582, + "chi2_min": 1385.3743896484375 + }, + { + "injected": false, + "period": 12.579136848449707, + "T0": 4.226824228778526, + "duration": 0.12552805244922638, + "depth": 0.0016740288119763136, + "SDE": 5.552786827087402, + "chi2_min": 1264.4737548828125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.004762173630297184, + "SDE": 14.101175308227539, + "chi2_min": 1356.297607421875 + }, + { + "injected": false, + "period": 2.6725428104400635, + "T0": 0.14406507034685756, + "duration": 0.06784135103225708, + "depth": 0.0009474533726461232, + "SDE": 6.514476299285889, + "chi2_min": 1290.8275146484375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005513247102499008, + "SDE": 14.359392166137695, + "chi2_min": 1438.327392578125 + }, + { + "injected": false, + "period": 0.6743714809417725, + "T0": 0.47082369012325387, + "duration": 0.038828302174806595, + "depth": 0.0007056481554172933, + "SDE": 6.8672099113464355, + "chi2_min": 1296.7098388671875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0056505389511585236, + "SDE": 14.969831466674805, + "chi2_min": 1335.3681640625 + }, + { + "injected": false, + "period": 3.817335605621338, + "T0": 0.36329775865793934, + "duration": 0.056766659021377563, + "depth": 0.001113416044972837, + "SDE": 4.920238018035889, + "chi2_min": 1314.1776123046875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00567090418189764, + "SDE": 14.075288772583008, + "chi2_min": 1247.64794921875 + }, + { + "injected": false, + "period": 8.94373893737793, + "T0": 4.204453678020741, + "duration": 0.07539563626050949, + "depth": 0.0017777399625629187, + "SDE": 4.999449729919434, + "chi2_min": 1302.4117431640625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005472837947309017, + "SDE": 14.669474601745605, + "chi2_min": 1300.7388916015625 + }, + { + "injected": false, + "period": 5.107228755950928, + "T0": 0.25593410245988935, + "duration": 0.0625511109828949, + "depth": 0.0013419573660939932, + "SDE": 5.736141681671143, + "chi2_min": 1301.5399169921875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005429895129054785, + "SDE": 13.518494606018066, + "chi2_min": 1338.432861328125 + }, + { + "injected": false, + "period": 8.641767501831055, + "T0": 4.278318558921512, + "duration": 0.0822959765791893, + "depth": 0.0016973762540146708, + "SDE": 4.410860061645508, + "chi2_min": 1327.6866455078125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005096357315778732, + "SDE": 13.462990760803223, + "chi2_min": 1241.7001953125 + }, + { + "injected": false, + "period": 10.220306396484375, + "T0": 4.387660793062423, + "duration": 0.07882454991340637, + "depth": 0.001610369305126369, + "SDE": 4.691564559936523, + "chi2_min": 1268.614013671875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0051406449638307095, + "SDE": 14.042201042175293, + "chi2_min": 1313.3265380859375 + }, + { + "injected": false, + "period": 9.36865520477295, + "T0": 9.22744536080586, + "duration": 0.1387048214673996, + "depth": 0.0016929314006119967, + "SDE": 6.051858425140381, + "chi2_min": 1253.9193115234375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005635188426822424, + "SDE": 14.192182540893555, + "chi2_min": 1322.7122802734375 + }, + { + "injected": false, + "period": 0.8091202974319458, + "T0": 0.4492196189062554, + "duration": 0.04125908017158508, + "depth": 0.0006857005064375699, + "SDE": 5.732414722442627, + "chi2_min": 1371.5711669921875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.1792505532503128, + "depth": 0.00515005411580205, + "SDE": 13.765022277832031, + "chi2_min": 1289.6336669921875 + }, + { + "injected": false, + "period": 0.8660217523574829, + "T0": 0.2381559870601997, + "duration": 0.06924363225698471, + "depth": 0.000580161577090621, + "SDE": 6.823153495788574, + "chi2_min": 1302.041015625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005201749037951231, + "SDE": 14.920594215393066, + "chi2_min": 1310.6806640625 + }, + { + "injected": false, + "period": 6.253728866577148, + "T0": 5.870805941826802, + "duration": 0.07388520240783691, + "depth": 0.0012998901074752212, + "SDE": 4.990450859069824, + "chi2_min": 1209.4974365234375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005448551848530769, + "SDE": 13.58593463897705, + "chi2_min": 1390.4388427734375 + }, + { + "injected": false, + "period": 12.104578018188477, + "T0": 9.877395361733647, + "duration": 0.09207913279533386, + "depth": 0.0019856933504343033, + "SDE": 5.132411479949951, + "chi2_min": 1289.7191162109375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.005371259059756994, + "SDE": 14.033452987670898, + "chi2_min": 1326.8525390625 + }, + { + "injected": false, + "period": 6.688271522521973, + "T0": 2.686991147148291, + "duration": 0.08342314511537552, + "depth": 0.0015159600879997015, + "SDE": 6.502882957458496, + "chi2_min": 1376.671142578125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00503845140337944, + "SDE": 14.093024253845215, + "chi2_min": 1418.729248046875 + }, + { + "injected": false, + "period": 2.585336923599243, + "T0": 0.923334637585171, + "duration": 0.13419054448604584, + "depth": 0.0006379691185429692, + "SDE": 5.249675273895264, + "chi2_min": 1297.920654296875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0051691788248717785, + "SDE": 14.503507614135742, + "chi2_min": 1335.154541015625 + }, + { + "injected": false, + "period": 1.1863054037094116, + "T0": 0.5719344635827, + "duration": 0.04040246084332466, + "depth": 0.000764436786994338, + "SDE": 4.693112850189209, + "chi2_min": 1279.0152587890625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005427448078989983, + "SDE": 13.62148380279541, + "chi2_min": 1318.234130859375 + }, + { + "injected": false, + "period": 2.7281653881073, + "T0": 1.4686617796954948, + "duration": 0.06830879300832748, + "depth": 0.000905516732018441, + "SDE": 5.483219146728516, + "chi2_min": 1256.6185302734375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005423018243163824, + "SDE": 13.093084335327148, + "chi2_min": 1284.7784423828125 + }, + { + "injected": false, + "period": 4.76552152633667, + "T0": 1.0766223941304887, + "duration": 0.06748615950345993, + "depth": 0.0013720967108383775, + "SDE": 5.666236877441406, + "chi2_min": 1268.8609619140625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.1792505532503128, + "depth": 0.00524185923859477, + "SDE": 13.730987548828125, + "chi2_min": 1468.949462890625 + }, + { + "injected": false, + "period": 5.954711437225342, + "T0": 4.0025587667688, + "duration": 0.06583552062511444, + "depth": 0.0015804577851668, + "SDE": 4.635071754455566, + "chi2_min": 1338.395751953125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3166635296710325, + "duration": 0.17486760020256042, + "depth": 0.005472453776746988, + "SDE": 13.930768966674805, + "chi2_min": 1231.414794921875 + }, + { + "injected": false, + "period": 0.7494922876358032, + "T0": 0.14383159056938233, + "duration": 0.06598714739084244, + "depth": 0.0004580834647640586, + "SDE": 5.942159652709961, + "chi2_min": 1183.9090576171875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00511926831677556, + "SDE": 13.571946144104004, + "chi2_min": 1362.548095703125 + }, + { + "injected": false, + "period": 2.8218910694122314, + "T0": 0.3113438265453894, + "duration": 0.07258859276771545, + "depth": 0.0010486795799806714, + "SDE": 6.7492289543151855, + "chi2_min": 1301.56494140625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005257213022559881, + "SDE": 14.49308967590332, + "chi2_min": 1288.70556640625 + }, + { + "injected": false, + "period": 7.533771991729736, + "T0": 2.4072671396336887, + "duration": 0.07120505720376968, + "depth": 0.0016296287067234516, + "SDE": 5.135932445526123, + "chi2_min": 1290.2734375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005214039236307144, + "SDE": 13.498370170593262, + "chi2_min": 1333.4521484375 + }, + { + "injected": false, + "period": 2.043039560317993, + "T0": 0.20179237219836565, + "duration": 0.046089161187410355, + "depth": 0.0010053182486444712, + "SDE": 5.474965572357178, + "chi2_min": 1390.2979736328125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.302647882457407, + "duration": 0.19306959211826324, + "depth": 0.005054525565356016, + "SDE": 13.49543285369873, + "chi2_min": 1318.240234375 + }, + { + "injected": false, + "period": 9.047518730163574, + "T0": 4.986207971831902, + "duration": 0.12417609244585037, + "depth": 0.0012691729934886098, + "SDE": 5.239851474761963, + "chi2_min": 1229.02001953125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.0051093571819365025, + "SDE": 15.082120895385742, + "chi2_min": 1269.2886962890625 + }, + { + "injected": false, + "period": 13.309419631958008, + "T0": 8.291711655584322, + "duration": 0.0860782042145729, + "depth": 0.0020279965829104185, + "SDE": 5.076119422912598, + "chi2_min": 1284.479736328125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005712154787033796, + "SDE": 13.651554107666016, + "chi2_min": 1391.5516357421875 + }, + { + "injected": false, + "period": 3.42227840423584, + "T0": 1.513876878042396, + "duration": 0.05473672226071358, + "depth": 0.0012891051592305303, + "SDE": 5.590603828430176, + "chi2_min": 1319.033935546875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005534757860004902, + "SDE": 14.234055519104004, + "chi2_min": 1310.23583984375 + }, + { + "injected": false, + "period": 13.635416984558105, + "T0": 4.660816806064474, + "duration": 0.18693023920059204, + "depth": 0.0013690313789993525, + "SDE": 5.641323566436768, + "chi2_min": 1203.140625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.1792505532503128, + "depth": 0.005294170696288347, + "SDE": 13.605644226074219, + "chi2_min": 1339.434326171875 + }, + { + "injected": false, + "period": 12.15611457824707, + "T0": 4.847994174497785, + "duration": 0.15128548443317413, + "depth": 0.0013391560642048717, + "SDE": 5.003466606140137, + "chi2_min": 1278.67333984375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005288905929774046, + "SDE": 14.548331260681152, + "chi2_min": 1395.673583984375 + }, + { + "injected": false, + "period": 9.978133201599121, + "T0": 3.989828930425375, + "duration": 0.23240043222904205, + "depth": 0.001154838828369975, + "SDE": 6.545147895812988, + "chi2_min": 1311.4876708984375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00547023443505168, + "SDE": 13.900687217712402, + "chi2_min": 1303.812255859375 + }, + { + "injected": false, + "period": 1.227888584136963, + "T0": 0.24339220282239182, + "duration": 0.0622534416615963, + "depth": 0.0007609375170432031, + "SDE": 6.777478218078613, + "chi2_min": 1254.4796142578125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004985042382031679, + "SDE": 14.515047073364258, + "chi2_min": 1355.400634765625 + }, + { + "injected": false, + "period": 5.7309746742248535, + "T0": 2.468525694331092, + "duration": 0.06500045210123062, + "depth": 0.0014444179832935333, + "SDE": 5.217517375946045, + "chi2_min": 1338.3822021484375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.004980752710253, + "SDE": 14.50423812866211, + "chi2_min": 1379.7135009765625 + }, + { + "injected": false, + "period": 3.958618640899658, + "T0": 1.5509364717303242, + "duration": 0.0574585385620594, + "depth": 0.001268385211005807, + "SDE": 5.37081241607666, + "chi2_min": 1282.2177734375 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005414345767349005, + "SDE": 15.570334434509277, + "chi2_min": 1338.760498046875 + }, + { + "injected": false, + "period": 12.286243438720703, + "T0": 0.6104409236496622, + "duration": 0.08381339907646179, + "depth": 0.001824214938096702, + "SDE": 6.343598365783691, + "chi2_min": 1332.7315673828125 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005437149666249752, + "SDE": 14.980276107788086, + "chi2_min": 1358.66748046875 + }, + { + "injected": false, + "period": 6.318080902099609, + "T0": 0.0469745786837219, + "duration": 0.06714829802513123, + "depth": 0.0013039936311542988, + "SDE": 4.6731061935424805, + "chi2_min": 1247.87646484375 + } + ] + }, + "old": { + "nlc": 5, + "total_s": 0.4165675728581846, + "per_call_s": [ + 0.08606805291492492, + 0.08085096499416977, + 0.08287583803758025, + 0.08341802400536835, + 0.08335469290614128 + ], + "ms_per_lc": 83.35469290614128, + "lc_per_s": 11.99692500968141, + "extrapolated": true, + "note": "per-LC median over 5 LCs", + "n_injected": 3, + "n_recovered": 3, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.214750289916992, + "median_sde_noise": 5.1948442459106445, + "per_lc": [ + { + "injected": true, + "period": 7.70003080368042, + "T0": 0.30158731341362, + "duration": 0.18374329805374146, + "depth": 0.005273154005408287, + "SDE": 14.214750289916992, + "chi2_min": 1366.7169189453125 + }, + { + "injected": false, + "period": 0.6225233674049377, + "T0": 0.875, + "duration": 0.039725493639707565, + "depth": 0.0005230337847024202, + "SDE": 4.7374186515808105, + "chi2_min": 1317.3992919921875 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 0.30158731341362, + "duration": 0.18374329805374146, + "depth": 0.004768824204802513, + "SDE": 14.500447273254395, + "chi2_min": 1427.902587890625 + }, + { + "injected": false, + "period": 4.131380081176758, + "T0": 0.30049261450767517, + "duration": 0.06124073639512062, + "depth": 0.001288519473746419, + "SDE": 5.6522698402404785, + "chi2_min": 1313.3834228515625 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 0.30158731341362, + "duration": 0.18374329805374146, + "depth": 0.005183448549360037, + "SDE": 13.707527160644531, + "chi2_min": 1279.4794921875 + } + ] + }, + "reference": { + "nlc": 1, + "total_s": 14.70412063098047, + "per_call_s": [ + 14.70412063098047 + ], + "ms_per_lc": 14704.12063098047, + "lc_per_s": 0.0680081471783546, + "extrapolated": true, + "note": "per-LC median over 1 LCs", + "n_injected": 1, + "n_recovered": 1, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 17.433094918772902, + "median_sde_noise": null, + "per_lc": [ + { + "injected": true, + "period": 7.707421629851162, + "T0": 2.3130252400704143, + "duration": 0.17014672798958713, + "depth": 0.9944062766363239, + "SDE": 17.433094918772902, + "chi2_min": null + } + ] + } + } + }, + "k2": { + "config": { + "ndata": 4320, + "baseline": 90.0, + "cadence": 0.020833333333333332, + "noise": 0.0008, + "inject_period": 12.4, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 45.0, + "nlc": 50 + }, + "nlc": 50, + "nperiods": 9672, + "impls": { + "new": { + "nlc": 50, + "total_s": 0.7236975010018796, + "times_s": [ + 0.7236975010018796 + ], + "ms_per_lc": 14.473950020037591, + "lc_per_s": 69.08964025823013, + "n_injected": 25, + "n_recovered": 25, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 25.313722610473633, + "median_sde_noise": 6.645591735839844, + "per_lc": [ + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.004352097399532795, + "SDE": 26.41286849975586, + "chi2_min": 4387.0771484375 + }, + { + "injected": false, + "period": 1.3685027360916138, + "T0": 0.9995278422767413, + "duration": 0.044523872435092926, + "depth": 0.0003865647013299167, + "SDE": 6.258840084075928, + "chi2_min": 4326.8408203125 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004342587199062109, + "SDE": 25.128662109375, + "chi2_min": 4408.6591796875 + }, + { + "injected": false, + "period": 1.567154884338379, + "T0": 0.6710433548500703, + "duration": 0.046581678092479706, + "depth": 0.00046604909584857523, + "SDE": 10.426676750183105, + "chi2_min": 4249.2431640625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.004444643389433622, + "SDE": 25.042335510253906, + "chi2_min": 4386.859375 + }, + { + "injected": false, + "period": 17.946809768676758, + "T0": 11.771186328499653, + "duration": 0.1949620395898819, + "depth": 0.0006966719520278275, + "SDE": 6.579500675201416, + "chi2_min": 4314.2119140625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.00431243097409606, + "SDE": 26.375844955444336, + "chi2_min": 4341.9091796875 + }, + { + "injected": false, + "period": 7.888498306274414, + "T0": 7.531212754637977, + "duration": 0.08388378471136093, + "depth": 0.0007113401079550385, + "SDE": 6.401275157928467, + "chi2_min": 4085.73876953125 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.204982191324234, + "depth": 0.004326032940298319, + "SDE": 26.117460250854492, + "chi2_min": 4431.56103515625 + }, + { + "injected": false, + "period": 1.7248963117599487, + "T0": 0.09257843054204251, + "duration": 0.14293743669986725, + "depth": 0.0002644819614943117, + "SDE": 8.722923278808594, + "chi2_min": 4256.3544921875 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19997018575668335, + "depth": 0.004363611340522766, + "SDE": 24.74551773071289, + "chi2_min": 4470.55859375 + }, + { + "injected": false, + "period": 40.31962203979492, + "T0": 12.79962811146072, + "duration": 0.1850813776254654, + "depth": 0.001074489438906312, + "SDE": 6.051089763641357, + "chi2_min": 4326.759765625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.0042357980273664, + "SDE": 25.487497329711914, + "chi2_min": 4373.689453125 + }, + { + "injected": false, + "period": 13.618805885314941, + "T0": 12.356419633092571, + "duration": 0.10573731362819672, + "depth": 0.0009254583856090903, + "SDE": 6.189550876617432, + "chi2_min": 4297.984375 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.004302197601646185, + "SDE": 24.595088958740234, + "chi2_min": 4261.193359375 + }, + { + "injected": false, + "period": 8.089868545532227, + "T0": 4.885035835718213, + "duration": 0.09111291915178299, + "depth": 0.0007423317874781787, + "SDE": 7.2754950523376465, + "chi2_min": 4085.354248046875 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.0042641134932637215, + "SDE": 23.71144676208496, + "chi2_min": 4317.3330078125 + }, + { + "injected": false, + "period": 15.671825408935547, + "T0": 11.627483488450707, + "duration": 0.36358538269996643, + "depth": 0.0004862357454840094, + "SDE": 5.54551887512207, + "chi2_min": 4251.71435546875 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.732052489198992, + "duration": 0.21007460355758667, + "depth": 0.0042679025791585445, + "SDE": 25.32743263244629, + "chi2_min": 4252.84814453125 + }, + { + "injected": false, + "period": 2.754897117614746, + "T0": 2.5983700068006783, + "duration": 0.08354046940803528, + "depth": 0.00038990896428003907, + "SDE": 6.645591735839844, + "chi2_min": 4304.2802734375 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.0041894433088600636, + "SDE": 25.313722610473633, + "chi2_min": 4441.63818359375 + }, + { + "injected": false, + "period": 7.901713848114014, + "T0": 5.554735825406851, + "duration": 0.10750557482242584, + "depth": 0.0006463827448897064, + "SDE": 6.50754976272583, + "chi2_min": 4282.33251953125 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.00431278720498085, + "SDE": 25.72516441345215, + "chi2_min": 4257.3173828125 + }, + { + "injected": false, + "period": 2.0137128829956055, + "T0": 1.3472117866492113, + "duration": 0.05591322481632233, + "depth": 0.0004975693300366402, + "SDE": 10.68542194366455, + "chi2_min": 4280.7685546875 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004413061309605837, + "SDE": 25.41738510131836, + "chi2_min": 4409.75390625 + }, + { + "injected": false, + "period": 16.01749610900879, + "T0": 4.732432745412893, + "duration": 0.09385470300912857, + "depth": 0.0008603514288552105, + "SDE": 5.5665788650512695, + "chi2_min": 4099.48876953125 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19997018575668335, + "depth": 0.004251678939908743, + "SDE": 26.01239776611328, + "chi2_min": 4506.17333984375 + }, + { + "injected": false, + "period": 10.265218734741211, + "T0": 3.1706764167317942, + "duration": 0.0893411710858345, + "depth": 0.000808034441433847, + "SDE": 8.316948890686035, + "chi2_min": 4252.4541015625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.004466493614017963, + "SDE": 24.81790542602539, + "chi2_min": 4458.2509765625 + }, + { + "injected": false, + "period": 30.56487464904785, + "T0": 7.08230056832997, + "duration": 0.1285296082496643, + "depth": 0.0011698486050590873, + "SDE": 5.639177322387695, + "chi2_min": 4209.0498046875 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.0043472908437252045, + "SDE": 25.853296279907227, + "chi2_min": 4367.650390625 + }, + { + "injected": false, + "period": 36.307926177978516, + "T0": 19.91623931560639, + "duration": 0.29323291778564453, + "depth": 0.000972222478594631, + "SDE": 6.6832427978515625, + "chi2_min": 4425.97998046875 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004358186852186918, + "SDE": 25.013660430908203, + "chi2_min": 4418.55126953125 + }, + { + "injected": false, + "period": 3.8394787311553955, + "T0": 3.5172907226911434, + "duration": 0.08880756050348282, + "depth": 0.0004855781444348395, + "SDE": 6.711667537689209, + "chi2_min": 4251.2158203125 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.204982191324234, + "depth": 0.0042197867296636105, + "SDE": 27.17059326171875, + "chi2_min": 4318.37890625 + }, + { + "injected": false, + "period": 1.1502342224121094, + "T0": 0.1958829591745257, + "duration": 0.04996860772371292, + "depth": 0.00035351532278582454, + "SDE": 7.501292705535889, + "chi2_min": 4534.52490234375 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.004392570350319147, + "SDE": 26.404085159301758, + "chi2_min": 4508.17822265625 + }, + { + "injected": false, + "period": 5.259787082672119, + "T0": 1.6824305120182999, + "duration": 0.07700253278017044, + "depth": 0.0005853439797647297, + "SDE": 6.906394958496094, + "chi2_min": 4316.62890625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.0045080301351845264, + "SDE": 25.257204055786133, + "chi2_min": 4411.8984375 + }, + { + "injected": false, + "period": 14.582316398620605, + "T0": 8.464501963214104, + "duration": 0.08873925358057022, + "depth": 0.0010340927401557565, + "SDE": 7.145528793334961, + "chi2_min": 4359.5087890625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.004241089802235365, + "SDE": 25.864206314086914, + "chi2_min": 4505.0234375 + }, + { + "injected": false, + "period": 12.45097541809082, + "T0": 9.849355446693153, + "duration": 0.14158391952514648, + "depth": 0.0007936642505228519, + "SDE": 8.454061508178711, + "chi2_min": 4300.4619140625 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.7385776951641674, + "duration": 0.21007460355758667, + "depth": 0.004096492659300566, + "SDE": 24.88788414001465, + "chi2_min": 4323.14990234375 + }, + { + "injected": false, + "period": 2.9074718952178955, + "T0": 1.8813054051288134, + "duration": 0.07331513613462448, + "depth": 0.0004352267715148628, + "SDE": 6.141500949859619, + "chi2_min": 4107.63916015625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.00426055071875453, + "SDE": 24.827207565307617, + "chi2_min": 4553.47021484375 + }, + { + "injected": false, + "period": 3.8546807765960693, + "T0": 3.842780059564987, + "duration": 0.20632818341255188, + "depth": 0.0003478155704215169, + "SDE": 5.401646614074707, + "chi2_min": 4368.59912109375 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004260950721800327, + "SDE": 24.611242294311523, + "chi2_min": 4400.51953125 + }, + { + "injected": false, + "period": 5.128723621368408, + "T0": 1.3880361595794426, + "duration": 0.11346686631441116, + "depth": 0.0004658329125959426, + "SDE": 6.783279895782471, + "chi2_min": 4368.8291015625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19997018575668335, + "depth": 0.004382762126624584, + "SDE": 24.896284103393555, + "chi2_min": 4545.61572265625 + }, + { + "injected": false, + "period": 1.5529592037200928, + "T0": 1.0412210721013935, + "duration": 0.09288113564252853, + "depth": 0.0003009258070960641, + "SDE": 6.297451496124268, + "chi2_min": 4323.4833984375 + } + ] + }, + "old": { + "skipped": "ndata cap" + }, + "reference": { + "nlc": 1, + "total_s": 21.475801305961795, + "per_call_s": [ + 21.475801305961795 + ], + "ms_per_lc": 21475.801305961795, + "lc_per_s": 0.046564036691957786, + "extrapolated": true, + "note": "per-LC median over 1 LCs", + "n_injected": 1, + "n_recovered": 1, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 30.963206358691103, + "median_sde_noise": null, + "per_lc": [ + { + "injected": true, + "period": 12.401754384696078, + "T0": 3.7201060631824645, + "duration": 0.19268825330556646, + "depth": 0.9956597462534411, + "SDE": 30.963206358691103, + "chi2_min": null + } + ] + } + } + }, + "tess-2min": { + "config": { + "ndata": 19710, + "baseline": 27.4, + "cadence": 0.001388888888888889, + "noise": 0.002, + "inject_period": 7.7, + "inject_depth": 0.005, + "period_min": 0.6, + "period_max": 13.7, + "nlc": 50 + }, + "nlc": 50, + "nperiods": 2497, + "impls": { + "new": { + "nlc": 50, + "total_s": 1.6093172129476443, + "times_s": [ + 1.6093172129476443 + ], + "ms_per_lc": 32.186344258952886, + "lc_per_s": 31.069076747411042, + "n_injected": 25, + "n_recovered": 25, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.725510597229004, + "median_sde_noise": 5.81863260269165, + "per_lc": [ + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005485763773322105, + "SDE": 14.625007629394531, + "chi2_min": 19986.646484375 + }, + { + "injected": false, + "period": 13.100994110107422, + "T0": 5.437705039673006, + "duration": 0.10182765871286392, + "depth": 0.000987470499239862, + "SDE": 7.187177658081055, + "chi2_min": 19991.27734375 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005453882738947868, + "SDE": 13.996513366699219, + "chi2_min": 20026.580078125 + }, + { + "injected": false, + "period": 0.727395236492157, + "T0": 0.3019376498355886, + "duration": 0.042890265583992004, + "depth": 0.00036336382618173957, + "SDE": 5.8260416984558105, + "chi2_min": 19321.81640625 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0054051559418439865, + "SDE": 14.713297843933105, + "chi2_min": 19669.765625 + }, + { + "injected": false, + "period": 2.640021324157715, + "T0": 0.4917686880570642, + "duration": 0.0764675959944725, + "depth": 0.00048310792772099376, + "SDE": 6.617506980895996, + "chi2_min": 19593.427734375 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0054057748056948185, + "SDE": 14.754934310913086, + "chi2_min": 19828.859375 + }, + { + "injected": false, + "period": 9.231582641601562, + "T0": 1.668764258751935, + "duration": 0.07619598507881165, + "depth": 0.0008226699428632855, + "SDE": 4.714282989501953, + "chi2_min": 20048.86328125 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005362111143767834, + "SDE": 14.330925941467285, + "chi2_min": 19451.40625 + }, + { + "injected": false, + "period": 1.5595471858978271, + "T0": 0.281584903400649, + "duration": 0.06259265542030334, + "depth": 0.0003787315508816391, + "SDE": 6.048738479614258, + "chi2_min": 19451.8203125 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005432445090264082, + "SDE": 14.942078590393066, + "chi2_min": 19835.658203125 + }, + { + "injected": false, + "period": 3.7597527503967285, + "T0": 3.551468894538374, + "duration": 0.09266479313373566, + "depth": 0.0005465586436912417, + "SDE": 5.56866979598999, + "chi2_min": 19562.216796875 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005425632931292057, + "SDE": 14.515064239501953, + "chi2_min": 19661.443359375 + }, + { + "injected": false, + "period": 5.938205242156982, + "T0": 1.8585079530804478, + "duration": 0.0977407768368721, + "depth": 0.0006803354481235147, + "SDE": 5.1869988441467285, + "chi2_min": 19645.716796875 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.00532762985676527, + "SDE": 14.817203521728516, + "chi2_min": 19854.83984375 + }, + { + "injected": false, + "period": 0.6239511370658875, + "T0": 0.1721244509631692, + "duration": 0.03426845371723175, + "depth": 0.00035405956441536546, + "SDE": 6.364353656768799, + "chi2_min": 19814.71875 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005372270941734314, + "SDE": 14.703107833862305, + "chi2_min": 19759.875 + }, + { + "injected": false, + "period": 1.7957980632781982, + "T0": 0.0708701585838174, + "duration": 0.049966782331466675, + "depth": 0.0004548485158011317, + "SDE": 5.303484916687012, + "chi2_min": 19886.9140625 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0056047262623906136, + "SDE": 14.878658294677734, + "chi2_min": 19847.30859375 + }, + { + "injected": false, + "period": 1.420212745666504, + "T0": 0.05407682774567846, + "duration": 0.060670167207717896, + "depth": 0.00034811272053048015, + "SDE": 5.3370771408081055, + "chi2_min": 19686.30078125 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005634222645312548, + "SDE": 15.200629234313965, + "chi2_min": 20082.625 + }, + { + "injected": false, + "period": 1.944218635559082, + "T0": 1.0748527127935859, + "duration": 0.04533376544713974, + "depth": 0.0005115983076393604, + "SDE": 6.226770401000977, + "chi2_min": 19728.376953125 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.00562666542828083, + "SDE": 14.830127716064453, + "chi2_min": 19887.3671875 + }, + { + "injected": false, + "period": 5.338284969329834, + "T0": 1.2329951883274148, + "duration": 0.2083013355731964, + "depth": 0.00045530812349170446, + "SDE": 5.81863260269165, + "chi2_min": 19457.34765625 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005390736740082502, + "SDE": 14.687355041503906, + "chi2_min": 19622.46484375 + }, + { + "injected": false, + "period": 1.9001942873001099, + "T0": 1.6714522132299692, + "duration": 0.1670754998922348, + "depth": 0.0003015141701325774, + "SDE": 6.128674507141113, + "chi2_min": 19683.650390625 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005256369709968567, + "SDE": 14.609891891479492, + "chi2_min": 19651.33203125 + }, + { + "injected": false, + "period": 2.132042646408081, + "T0": 1.8807319745508266, + "duration": 0.051615022122859955, + "depth": 0.0005292932619340718, + "SDE": 5.569215297698975, + "chi2_min": 19577.80078125 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005402362439781427, + "SDE": 14.439190864562988, + "chi2_min": 19436.732421875 + }, + { + "injected": false, + "period": 2.430079221725464, + "T0": 2.2653281420587916, + "duration": 0.13144873082637787, + "depth": 0.00038963276892900467, + "SDE": 6.2423787117004395, + "chi2_min": 19901.732421875 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17922694981098175, + "depth": 0.005089751910418272, + "SDE": 14.021259307861328, + "chi2_min": 20220.5703125 + }, + { + "injected": false, + "period": 9.231582641601562, + "T0": 3.019791075150806, + "duration": 0.07810574769973755, + "depth": 0.0008826106204651296, + "SDE": 5.6142354011535645, + "chi2_min": 19451.4296875 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005317771341651678, + "SDE": 15.05292797088623, + "chi2_min": 19643.59765625 + }, + { + "injected": false, + "period": 8.733040809631348, + "T0": 1.2241375973440398, + "duration": 0.07479896396398544, + "depth": 0.0009044495527632535, + "SDE": 5.337958335876465, + "chi2_min": 19883.51953125 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005483758170157671, + "SDE": 14.85096549987793, + "chi2_min": 19639.47265625 + }, + { + "injected": false, + "period": 1.0538432598114014, + "T0": 0.8465298903467868, + "duration": 0.04974828660488129, + "depth": 0.00036485373857431114, + "SDE": 7.628678798675537, + "chi2_min": 19180.42578125 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0054765734821558, + "SDE": 14.937609672546387, + "chi2_min": 19795.39453125 + }, + { + "injected": false, + "period": 1.7158273458480835, + "T0": 1.438457715678659, + "duration": 0.07876930385828018, + "depth": 0.00038677072734571993, + "SDE": 7.276026725769043, + "chi2_min": 19453.857421875 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0053500221110880375, + "SDE": 14.881278991699219, + "chi2_min": 20215.64453125 + }, + { + "injected": false, + "period": 9.213768005371094, + "T0": 3.8128516220795063, + "duration": 0.07614698261022568, + "depth": 0.0008834435138851404, + "SDE": 5.695574760437012, + "chi2_min": 19582.09765625 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0054364390671253204, + "SDE": 14.983465194702148, + "chi2_min": 19810.994140625 + }, + { + "injected": false, + "period": 1.186469316482544, + "T0": 0.444925993680954, + "duration": 0.04687422513961792, + "depth": 0.0003952206752728671, + "SDE": 5.102463245391846, + "chi2_min": 19782.31640625 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0054940530098974705, + "SDE": 14.933070182800293, + "chi2_min": 19692.0625 + }, + { + "injected": false, + "period": 1.7699131965637207, + "T0": 1.468044076797554, + "duration": 0.04972551763057709, + "depth": 0.0005097914836369455, + "SDE": 6.834410667419434, + "chi2_min": 19890.083984375 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0053437440656125546, + "SDE": 14.725510597229004, + "chi2_min": 19796.72265625 + }, + { + "injected": false, + "period": 1.6712085008621216, + "T0": 0.23874408222442334, + "duration": 0.05521129071712494, + "depth": 0.0004521652008406818, + "SDE": 6.857421398162842, + "chi2_min": 19370.162109375 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005551040638238192, + "SDE": 14.696364402770996, + "chi2_min": 19685.80078125 + }, + { + "injected": false, + "period": 0.9706023335456848, + "T0": 0.9521787137664184, + "duration": 0.07192568480968475, + "depth": 0.00030540055013261735, + "SDE": 5.069840908050537, + "chi2_min": 20024.76953125 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005364942830055952, + "SDE": 14.3045015335083, + "chi2_min": 19449.197265625 + }, + { + "injected": false, + "period": 3.3878562450408936, + "T0": 2.242408262616337, + "duration": 0.054552532732486725, + "depth": 0.0006831723148934543, + "SDE": 5.030765056610107, + "chi2_min": 19772.6015625 + } + ] + }, + "old": { + "skipped": "ndata cap" + }, + "reference": { + "nlc": 1, + "total_s": 20.703610604046844, + "per_call_s": [ + 20.703610604046844 + ], + "ms_per_lc": 20703.610604046844, + "lc_per_s": 0.048300753869691425, + "extrapolated": true, + "note": "per-LC median over 1 LCs", + "n_injected": 1, + "n_recovered": 1, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 15.311789171693592, + "median_sde_noise": null, + "per_lc": [ + { + "injected": true, + "period": 7.697715495144377, + "T0": 2.3152336551975656, + "duration": 0.15490975491224693, + "depth": 0.9942281780912013, + "SDE": 15.311789171693592, + "chi2_min": null + } + ] + } + } + }, + "tess-yr": { + "config": { + "ndata": 16850, + "baseline": 351.0, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 21.7, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 175.0, + "nlc": 20 + }, + "nlc": 20, + "nperiods": 42001, + "impls": { + "new": { + "nlc": 20, + "total_s": 2.329541099956259, + "times_s": [ + 2.329541099956259 + ], + "ms_per_lc": 116.47705499781296, + "lc_per_s": 8.585381902201911, + "n_injected": 10, + "n_recovered": 10, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 52.50939750671387, + "median_sde_noise": 8.135910511016846, + "per_lc": [ + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004285216797143221, + "SDE": 51.96808624267578, + "chi2_min": 17045.296875 + }, + { + "injected": false, + "period": 42.48393630981445, + "T0": 24.362156216019912, + "duration": 0.15449827909469604, + "depth": 0.0008234648266807199, + "SDE": 8.125212669372559, + "chi2_min": 16853.18359375 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004315285012125969, + "SDE": 53.290836334228516, + "chi2_min": 17079.37109375 + }, + { + "injected": false, + "period": 3.215691566467285, + "T0": 2.7022411507869606, + "duration": 0.05919283628463745, + "depth": 0.00034805055474862456, + "SDE": 7.1917243003845215, + "chi2_min": 16563.556640625 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004378132522106171, + "SDE": 51.542381286621094, + "chi2_min": 16690.8125 + }, + { + "injected": false, + "period": 115.44019317626953, + "T0": 40.610479753671825, + "duration": 0.19526782631874084, + "depth": 0.0012061776360496879, + "SDE": 8.25966739654541, + "chi2_min": 16943.583984375 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004271373152732849, + "SDE": 53.543060302734375, + "chi2_min": 16960.623046875 + }, + { + "injected": false, + "period": 13.20435905456543, + "T0": 1.339143794434733, + "duration": 0.2093072384595871, + "depth": 0.00039137076237238944, + "SDE": 8.067180633544922, + "chi2_min": 16618.20703125 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004417840391397476, + "SDE": 53.131507873535156, + "chi2_min": 17073.46484375 + }, + { + "injected": false, + "period": 1.0810301303863525, + "T0": 0.8323784887314218, + "duration": 0.03727799281477928, + "depth": 0.00030445540323853493, + "SDE": 11.814228057861328, + "chi2_min": 16803.59375 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004163388162851334, + "SDE": 51.01511764526367, + "chi2_min": 17136.814453125 + }, + { + "injected": false, + "period": 35.858131408691406, + "T0": 3.57559711400188, + "duration": 0.3145294189453125, + "depth": 0.0005174473044462502, + "SDE": 7.057640552520752, + "chi2_min": 16644.427734375 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2409670054912567, + "depth": 0.004405491054058075, + "SDE": 53.55682373046875, + "chi2_min": 17381.18359375 + }, + { + "injected": false, + "period": 1.4476821422576904, + "T0": 1.3089501248304032, + "duration": 0.04536651819944382, + "depth": 0.0002738697803579271, + "SDE": 8.49048900604248, + "chi2_min": 17168.869140625 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.00433772336691618, + "SDE": 52.23996353149414, + "chi2_min": 17070.54296875 + }, + { + "injected": false, + "period": 158.6757354736328, + "T0": 94.3506197494853, + "duration": 0.4914354979991913, + "depth": 0.0008981031714938581, + "SDE": 7.7233781814575195, + "chi2_min": 16733.61328125 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004398007411509752, + "SDE": 52.778831481933594, + "chi2_min": 17030.78125 + }, + { + "injected": false, + "period": 71.84587860107422, + "T0": 33.78735158730137, + "duration": 0.17517852783203125, + "depth": 0.0010416145669296384, + "SDE": 8.146608352661133, + "chi2_min": 16928.7578125 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.00430144090205431, + "SDE": 50.41120910644531, + "chi2_min": 16781.74609375 + }, + { + "injected": false, + "period": 111.1105728149414, + "T0": 106.63255052949808, + "duration": 0.23501992225646973, + "depth": 0.0012142080813646317, + "SDE": 10.223708152770996, + "chi2_min": 16825.001953125 + } + ] + }, + "old": { + "skipped": "ndata cap" + }, + "reference": { + "nlc": 1, + "total_s": 111.08370612398721, + "per_call_s": [ + 111.08370612398721 + ], + "ms_per_lc": 111083.70612398721, + "lc_per_s": 0.009002220351595397, + "extrapolated": true, + "note": "per-LC median over 1 LCs", + "n_injected": 1, + "n_recovered": 1, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 54.94634090944878, + "median_sde_noise": null, + "per_lc": [ + { + "injected": true, + "period": 21.70040209536575, + "T0": 6.508462894486594, + "duration": 0.23561813482228744, + "depth": 0.9957636265216906, + "SDE": 54.94634090944878, + "chi2_min": null + } + ] + } + } + }, + "kepler-4yr": { + "config": { + "ndata": 65440, + "baseline": 1363.0, + "cadence": 0.020833333333333332, + "noise": 0.0006, + "inject_period": 41.3, + "inject_depth": 0.003, + "period_min": 0.6, + "period_max": 500.0, + "nlc": 10 + }, + "nlc": 10, + "nperiods": 171688, + "impls": { + "new": { + "nlc": 10, + "total_s": 15.758871630998328, + "times_s": [ + 15.758871630998328 + ], + "ms_per_lc": 1575.8871630998328, + "lc_per_s": 0.6345631993301857, + "n_injected": 5, + "n_recovered": 5, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 99.27885437011719, + "median_sde_noise": 8.790546417236328, + "per_lc": [ + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003353152424097061, + "SDE": 99.46661376953125, + "chi2_min": 65888.8671875 + }, + { + "injected": false, + "period": 55.92778396606445, + "T0": 50.18960453722707, + "duration": 0.16932646930217743, + "depth": 0.0003129727265331894, + "SDE": 8.594135284423828, + "chi2_min": 65561.171875 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003339743707329035, + "SDE": 100.876953125, + "chi2_min": 66294.484375 + }, + { + "injected": false, + "period": 131.69247436523438, + "T0": 60.8605908603713, + "duration": 0.20403198897838593, + "depth": 0.000416730938013643, + "SDE": 8.790546417236328, + "chi2_min": 65907.7109375 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0033489209599792957, + "SDE": 98.255615234375, + "chi2_min": 66182.921875 + }, + { + "injected": false, + "period": 96.05792236328125, + "T0": 50.61724713786316, + "duration": 0.24719244241714478, + "depth": 0.000355874712113291, + "SDE": 11.384912490844727, + "chi2_min": 65324.4375 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003390833968296647, + "SDE": 98.79753112792969, + "chi2_min": 66280.8515625 + }, + { + "injected": false, + "period": 164.4737091064453, + "T0": 46.597844866974356, + "duration": 0.23087593913078308, + "depth": 0.0004219160182401538, + "SDE": 8.307422637939453, + "chi2_min": 65834.796875 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003344569355249405, + "SDE": 99.27885437011719, + "chi2_min": 66655.078125 + }, + { + "injected": false, + "period": 2.184530735015869, + "T0": 1.3664060570654044, + "duration": 0.10407035797834396, + "depth": 7.646237645531073e-05, + "SDE": 9.044288635253906, + "chi2_min": 65125.0859375 + } + ] + }, + "old": { + "skipped": "ndata cap" + }, + "reference": { + "skipped": "expected CPU runtime >~15 min; pass --ref-all to run" + } + } + } + }, + "env": { + "python": "3.11.10", + "numpy": "2.4.6", + "hostname": "b09d596f0cce", + "cpu_count": 64, + "cuvarbase": "1.0.0", + "pycuda": "2026.1", + "cuda_driver_version": 13000, + "gpu": "NVIDIA RTX A5000", + "compute_capability": "8.6", + "nvcc": "Cuda compilation tools, release 12.4, V12.4.131" + } +} \ No newline at end of file diff --git a/benchmarks/results/tls_survey_jul2026/tls_survey_a5000_final.json b/benchmarks/results/tls_survey_jul2026/tls_survey_a5000_final.json new file mode 100644 index 0000000..f663b32 --- /dev/null +++ b/benchmarks/results/tls_survey_jul2026/tls_survey_a5000_final.json @@ -0,0 +1,2269 @@ +{ + "script": "benchmark_tls_survey.py", + "timestamp": "2026-07-06T18:06:16", + "args": { + "regimes": "tess-ffi,k2,tess-2min,tess-yr,kepler-4yr", + "nlc": null, + "impls": "new", + "ref_nlc": 1, + "old_nlc": 5, + "n_iter": 1, + "output": "tls_survey_a5000_final.json", + "quick": false, + "ref_all": false + }, + "regimes": { + "tess-ffi": { + "config": { + "ndata": 1310, + "baseline": 27.4, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 7.7, + "inject_depth": 0.005, + "period_min": 0.6, + "period_max": 13.7, + "nlc": 100 + }, + "nlc": 100, + "nperiods": 2486, + "impls": { + "new": { + "nlc": 100, + "total_s": 0.12544582097325474, + "times_s": [ + 0.12544582097325474 + ], + "ms_per_lc": 1.2544582097325474, + "lc_per_s": 797.156885930223, + "n_injected": 50, + "n_recovered": 50, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.215956254814571, + "median_sde_noise": 5.443090003635092, + "per_lc": [ + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005532108247280121, + "SDE": 14.065390751689842, + "chi2_min": 1336.7557435313201 + }, + { + "injected": false, + "period": 0.6225233674049377, + "T0": 0.542300333010111, + "duration": 0.037806544452905655, + "depth": 0.0005694830324500799, + "SDE": 4.9503392833795115, + "chi2_min": 1315.3825465302093 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005046018864959478, + "SDE": 14.353723878887898, + "chi2_min": 1393.1030901098823 + }, + { + "injected": false, + "period": 4.131380081176758, + "T0": 1.2414492021177352, + "duration": 0.06124073639512062, + "depth": 0.00128852017223835, + "SDE": 5.341763840837246, + "chi2_min": 1313.3827822895487 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005532108247280121, + "SDE": 13.579242124218501, + "chi2_min": 1225.935215715939 + }, + { + "injected": false, + "period": 6.83004903793335, + "T0": 3.3232153407358425, + "duration": 0.15217697620391846, + "depth": 0.001029684324748814, + "SDE": 5.390536614360936, + "chi2_min": 1240.1715078378356 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005443227011710405, + "SDE": 14.371898343022762, + "chi2_min": 1269.001673041523 + }, + { + "injected": false, + "period": 1.3832758665084839, + "T0": 1.2062232874457806, + "duration": 0.0404709056019783, + "depth": 0.001005177036859095, + "SDE": 6.775107403625014, + "chi2_min": 1265.1381991709252 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00549427792429924, + "SDE": 14.17301640116733, + "chi2_min": 1249.6949432980077 + }, + { + "injected": false, + "period": 3.7197482585906982, + "T0": 1.5470102355227056, + "duration": 0.08362992107868195, + "depth": 0.0011062233243137598, + "SDE": 4.313070302235385, + "chi2_min": 1306.5296519060553 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00537601625546813, + "SDE": 13.259800657398372, + "chi2_min": 1383.9029934304917 + }, + { + "injected": false, + "period": 3.789888858795166, + "T0": 2.661259939658663, + "duration": 0.06252489984035492, + "depth": 0.001284703379496932, + "SDE": 5.880022989926391, + "chi2_min": 1278.525860381444 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005833111237734556, + "SDE": 14.21540329245873, + "chi2_min": 1307.3178590593716 + }, + { + "injected": false, + "period": 0.694443941116333, + "T0": 0.5409164779852347, + "duration": 0.043291110545396805, + "depth": 0.0007188625750131905, + "SDE": 5.5175769196799695, + "chi2_min": 1375.8015752078236 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0054616364650428295, + "SDE": 14.35625719464975, + "chi2_min": 1400.4625896043808 + }, + { + "injected": false, + "period": 0.9697667956352234, + "T0": 0.6234215032222714, + "duration": 0.04170956835150719, + "depth": 0.0007615210488438606, + "SDE": 5.514336562681269, + "chi2_min": 1345.5726786362516 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005138108506798744, + "SDE": 14.902654451537112, + "chi2_min": 1374.5640473015765 + }, + { + "injected": false, + "period": 8.122530937194824, + "T0": 7.832263005316975, + "duration": 0.08061356842517853, + "depth": 0.001534505863673985, + "SDE": 5.39251678972409, + "chi2_min": 1408.3131930415202 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005546618718653917, + "SDE": 14.285447421157015, + "chi2_min": 1320.0360381533574 + }, + { + "injected": false, + "period": 6.6303558349609375, + "T0": 1.8257501173602577, + "duration": 0.09650145471096039, + "depth": 0.0013269108021631837, + "SDE": 6.504767090686456, + "chi2_min": 1293.2735987886438 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0055886139161884785, + "SDE": 14.409292504387171, + "chi2_min": 1236.1293730040288 + }, + { + "injected": false, + "period": 3.265150547027588, + "T0": 1.6735373315951279, + "duration": 0.0594947412610054, + "depth": 0.001139817526564002, + "SDE": 4.939560202740602, + "chi2_min": 1306.6482895325398 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005358264781534672, + "SDE": 14.037121530449207, + "chi2_min": 1378.8564958646666 + }, + { + "injected": false, + "period": 0.9069516062736511, + "T0": 0.4873173068018559, + "duration": 0.04285912215709686, + "depth": 0.0006940899766050279, + "SDE": 7.2372310451470225, + "chi2_min": 1326.8709772525024 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005511269439011812, + "SDE": 14.500004799996965, + "chi2_min": 1315.768630715941 + }, + { + "injected": false, + "period": 6.818082332611084, + "T0": 0.19493036610213732, + "duration": 0.06887488067150116, + "depth": 0.001466379500925541, + "SDE": 4.695511531922886, + "chi2_min": 1332.3330495656523 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005003546830266714, + "SDE": 14.708295692721075, + "chi2_min": 1274.4610292007467 + }, + { + "injected": false, + "period": 1.3818519115447998, + "T0": 0.3538014247310741, + "duration": 0.040457021445035934, + "depth": 0.0008182328892871737, + "SDE": 6.284758092136365, + "chi2_min": 1271.7957420160972 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005669730249792337, + "SDE": 15.411972700141082, + "chi2_min": 1376.2414849254828 + }, + { + "injected": false, + "period": 9.743551254272461, + "T0": 5.753463031568231, + "duration": 0.09000206738710403, + "depth": 0.0015667054103687406, + "SDE": 5.385836408139612, + "chi2_min": 1213.2532298462943 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.18374329805374146, + "depth": 0.005207412876188755, + "SDE": 14.868149526782913, + "chi2_min": 1277.8260611819942 + }, + { + "injected": false, + "period": 3.751904010772705, + "T0": 3.4951949631796992, + "duration": 0.05644047260284424, + "depth": 0.0012609766563400626, + "SDE": 4.929817718229013, + "chi2_min": 1313.6198509818798 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.18374329805374146, + "depth": 0.004843113943934441, + "SDE": 14.53650301024676, + "chi2_min": 1386.7924769026886 + }, + { + "injected": false, + "period": 12.579136848449707, + "T0": 4.226824228778526, + "duration": 0.12552805244922638, + "depth": 0.0016740263672545552, + "SDE": 5.493663217546093, + "chi2_min": 1264.473948842068 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.004762181080877781, + "SDE": 14.148837291732566, + "chi2_min": 1356.2967423676214 + }, + { + "injected": false, + "period": 2.6725428104400635, + "T0": 0.14387011199786048, + "duration": 0.05565265938639641, + "depth": 0.0010715341195464134, + "SDE": 6.350914261360382, + "chi2_min": 1289.7367575326448 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005513254553079605, + "SDE": 14.373714189776125, + "chi2_min": 1438.3267171983498 + }, + { + "injected": false, + "period": 0.6743714809417725, + "T0": 0.47082369012325387, + "duration": 0.038828302174806595, + "depth": 0.0007056446629576385, + "SDE": 6.976825838284036, + "chi2_min": 1296.7100488048077 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005650545936077833, + "SDE": 15.005956551762928, + "chi2_min": 1335.367667329123 + }, + { + "injected": false, + "period": 3.817335605621338, + "T0": 0.3609841388095205, + "duration": 0.06267549097537994, + "depth": 0.0010340978624299169, + "SDE": 5.272298794654755, + "chi2_min": 1315.3716891212723 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005670913495123386, + "SDE": 14.08645401077787, + "chi2_min": 1247.6468554586909 + }, + { + "injected": false, + "period": 8.94373893737793, + "T0": 4.204453678020741, + "duration": 0.07539563626050949, + "depth": 0.0017777406610548496, + "SDE": 4.767811022728785, + "chi2_min": 1302.41173783788 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005472847260534763, + "SDE": 14.71144953376925, + "chi2_min": 1300.7378989330853 + }, + { + "injected": false, + "period": 1.083532452583313, + "T0": 0.43690821784262823, + "duration": 0.05275972932577133, + "depth": 0.0006725414423272014, + "SDE": 5.844557773042149, + "chi2_min": 1303.3270971047903 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005429901648312807, + "SDE": 13.581099288039903, + "chi2_min": 1338.4324806558413 + }, + { + "injected": false, + "period": 3.751904010772705, + "T0": 1.6210399439368501, + "duration": 0.05644047260284424, + "depth": 0.0013095358153805137, + "SDE": 4.520674549124327, + "chi2_min": 1327.7450767907026 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005096363835036755, + "SDE": 13.503372284160607, + "chi2_min": 1241.699730173737 + }, + { + "injected": false, + "period": 5.536378383636475, + "T0": 2.694534725723358, + "duration": 0.07094460725784302, + "depth": 0.0013462472707033157, + "SDE": 4.509943126680122, + "chi2_min": 1267.498920703772 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005140651483088732, + "SDE": 14.075288318406649, + "chi2_min": 1313.3261367914786 + }, + { + "injected": false, + "period": 9.36865520477295, + "T0": 9.22744536080586, + "duration": 0.1387048214673996, + "depth": 0.0016929280245676637, + "SDE": 6.098590264772476, + "chi2_min": 1253.9192065986254 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005635196343064308, + "SDE": 14.216509217170412, + "chi2_min": 1322.711499255337 + }, + { + "injected": false, + "period": 0.8091202974319458, + "T0": 0.4492196189062554, + "duration": 0.04125908017158508, + "depth": 0.0006857021362520754, + "SDE": 5.719165778385463, + "chi2_min": 1371.571016880274 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.18374329805374146, + "depth": 0.005087862256914377, + "SDE": 13.78431724494761, + "chi2_min": 1289.7056162390122 + }, + { + "injected": false, + "period": 0.8660217523574829, + "T0": 0.2383568104642464, + "duration": 0.06924357265233994, + "depth": 0.000580215360969305, + "SDE": 6.840602505257836, + "chi2_min": 1302.0461920367197 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005201755557209253, + "SDE": 14.966413194156804, + "chi2_min": 1310.6803436341113 + }, + { + "injected": false, + "period": 6.253728866577148, + "T0": 5.870805941826802, + "duration": 0.07388520240783691, + "depth": 0.0012998866150155663, + "SDE": 5.263553497728533, + "chi2_min": 1209.4973824857957 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005448559299111366, + "SDE": 13.623365245620368, + "chi2_min": 1390.4382307294914 + }, + { + "injected": false, + "period": 12.104578018188477, + "T0": 9.877395361733647, + "duration": 0.09207913279533386, + "depth": 0.001985683338716626, + "SDE": 5.286762580365337, + "chi2_min": 1289.7191295226003 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.005371253006160259, + "SDE": 14.089673848773986, + "chi2_min": 1326.8539697531978 + }, + { + "injected": false, + "period": 1.4328784942626953, + "T0": 1.2479081935049408, + "duration": 0.04094899445772171, + "depth": 0.0009649074636399746, + "SDE": 6.146771137919548, + "chi2_min": 1376.8769192147242 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005038459785282612, + "SDE": 14.131821442560385, + "chi2_min": 1418.7284940720592 + }, + { + "injected": false, + "period": 2.585336923599243, + "T0": 0.923334637585171, + "duration": 0.13419054448604584, + "depth": 0.0006379721453413367, + "SDE": 5.25585444090269, + "chi2_min": 1297.9203697652006 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0051691848784685135, + "SDE": 14.536860915078682, + "chi2_min": 1335.154218438021 + }, + { + "injected": false, + "period": 1.1863054037094116, + "T0": 0.5719344635827, + "duration": 0.04040246084332466, + "depth": 0.000764436786994338, + "SDE": 4.749610142414918, + "chi2_min": 1279.015192561413 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0054274569265544415, + "SDE": 13.665248005840278, + "chi2_min": 1318.2331768535635 + }, + { + "injected": false, + "period": 2.7281653881073, + "T0": 1.4686617796954948, + "duration": 0.06830879300832748, + "depth": 0.0009055134141817689, + "SDE": 5.017592787824173, + "chi2_min": 1256.61867619463 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005423026625066996, + "SDE": 13.10426825832789, + "chi2_min": 1284.7775721516596 + }, + { + "injected": false, + "period": 4.76552152633667, + "T0": 1.076287644484374, + "duration": 0.06748615950345993, + "depth": 0.001369902165606618, + "SDE": 5.838513866931736, + "chi2_min": 1268.924454853593 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005303625948727131, + "SDE": 13.768917576085652, + "chi2_min": 1469.3855329483195 + }, + { + "injected": false, + "period": 5.954711437225342, + "T0": 4.0025587667688, + "duration": 0.06583552062511444, + "depth": 0.0015804474242031574, + "SDE": 4.6201746689994785, + "chi2_min": 1338.3957556418723 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3166635296710325, + "duration": 0.17486760020256042, + "depth": 0.00547246215865016, + "SDE": 13.970445047605669, + "chi2_min": 1231.4136864085472 + }, + { + "injected": false, + "period": 0.7494922876358032, + "T0": 0.14383159056938233, + "duration": 0.06598714739084244, + "depth": 0.00045808343566022813, + "SDE": 5.95458977497551, + "chi2_min": 1183.9089290347831 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005119277164340019, + "SDE": 13.60063329091786, + "chi2_min": 1362.5470870930055 + }, + { + "injected": false, + "period": 2.8218910694122314, + "T0": 0.3113438265453894, + "duration": 0.07258859276771545, + "depth": 0.0010486793471500278, + "SDE": 6.400881085852153, + "chi2_min": 1301.5649681369214 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005257221404463053, + "SDE": 14.531584381902036, + "chi2_min": 1288.7046099807844 + }, + { + "injected": false, + "period": 7.533771991729736, + "T0": 2.4072671396336887, + "duration": 0.07120505720376968, + "depth": 0.0016296235844492912, + "SDE": 5.648053038946863, + "chi2_min": 1290.2735534736444 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005214043892920017, + "SDE": 13.50181630864038, + "chi2_min": 1333.4523123305858 + }, + { + "injected": false, + "period": 2.045438051223755, + "T0": 0.19033353368033445, + "duration": 0.04844745248556137, + "depth": 0.0009628356783650815, + "SDE": 5.736909765326355, + "chi2_min": 1390.8257634245467 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.302647882457407, + "duration": 0.19306959211826324, + "depth": 0.005054534412920475, + "SDE": 13.526842247909006, + "chi2_min": 1318.2392164019288 + }, + { + "injected": false, + "period": 9.047518730163574, + "T0": 4.986207971831902, + "duration": 0.12417609244585037, + "depth": 0.0012691774172708392, + "SDE": 5.13026950088749, + "chi2_min": 1229.019885531746 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.005109364632517099, + "SDE": 15.091513974060161, + "chi2_min": 1269.2879464986113 + }, + { + "injected": false, + "period": 4.433368682861328, + "T0": 3.8600783631616196, + "duration": 0.059669382870197296, + "depth": 0.0014127626782283187, + "SDE": 5.318909771098138, + "chi2_min": 1282.9852399707484 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00571216456592083, + "SDE": 13.68735145866488, + "chi2_min": 1391.5502979665098 + }, + { + "injected": false, + "period": 3.42227840423584, + "T0": 1.513876878042396, + "duration": 0.05473672226071358, + "depth": 0.0012891065562143922, + "SDE": 5.639916325583477, + "chi2_min": 1319.0337806769976 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005534767638891935, + "SDE": 14.290255137567247, + "chi2_min": 1310.234607494101 + }, + { + "injected": false, + "period": 13.635416984558105, + "T0": 4.660816806064474, + "duration": 0.1823594868183136, + "depth": 0.001385409850627184, + "SDE": 5.697635637815957, + "chi2_min": 1203.2160460078271 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005357676651328802, + "SDE": 13.642723230186835, + "chi2_min": 1339.592726568851 + }, + { + "injected": false, + "period": 12.15611457824707, + "T0": 4.847994174497785, + "duration": 0.15128548443317413, + "depth": 0.0013391552492976189, + "SDE": 5.115254037085747, + "chi2_min": 1278.6733893042583 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0052889143116772175, + "SDE": 14.590804903503678, + "chi2_min": 1395.672670674071 + }, + { + "injected": false, + "period": 9.978133201599121, + "T0": 3.989828930425375, + "duration": 0.23240043222904205, + "depth": 0.001154838944785297, + "SDE": 6.614594199597157, + "chi2_min": 1311.4876419213956 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0054702446796, + "SDE": 13.901584858470857, + "chi2_min": 1303.8109990226483 + }, + { + "injected": false, + "period": 1.227888584136963, + "T0": 0.24339220282239182, + "duration": 0.06381379067897797, + "depth": 0.0007502195076085627, + "SDE": 6.699389113051831, + "chi2_min": 1254.5677523085624 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0049850489012897015, + "SDE": 14.54917558185404, + "chi2_min": 1355.400272127356 + }, + { + "injected": false, + "period": 2.2177605628967285, + "T0": 1.0043958503840145, + "duration": 0.06375162303447723, + "depth": 0.0008952956413850188, + "SDE": 5.1197930289375355, + "chi2_min": 1339.4699305699805 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.004980760160833597, + "SDE": 14.525513153103892, + "chi2_min": 1379.7126956069637 + }, + { + "injected": false, + "period": 3.958618640899658, + "T0": 1.5509364717303242, + "duration": 0.0574585385620594, + "depth": 0.0012683860259130597, + "SDE": 4.945356773245486, + "chi2_min": 1282.2177474202194 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005414358805865049, + "SDE": 15.56512061302323, + "chi2_min": 1338.7585082855128 + }, + { + "injected": false, + "period": 12.286243438720703, + "T0": 0.6104409236496622, + "duration": 0.08381339907646179, + "depth": 0.0018242186633870006, + "SDE": 6.411775274553496, + "chi2_min": 1332.7316477155935 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005437161773443222, + "SDE": 15.014119441824953, + "chi2_min": 1358.6656671348069 + }, + { + "injected": false, + "period": 6.318080902099609, + "T0": 0.0469745786837219, + "duration": 0.06714829802513123, + "depth": 0.0013039918849244714, + "SDE": 4.801563086659648, + "chi2_min": 1247.8763909035313 + } + ] + } + } + }, + "k2": { + "config": { + "ndata": 4320, + "baseline": 90.0, + "cadence": 0.020833333333333332, + "noise": 0.0008, + "inject_period": 12.4, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 45.0, + "nlc": 50 + }, + "nlc": 50, + "nperiods": 9672, + "impls": { + "new": { + "nlc": 50, + "total_s": 0.1552676890278235, + "times_s": [ + 0.1552676890278235 + ], + "ms_per_lc": 3.10535378055647, + "lc_per_s": 322.0245004808447, + "n_injected": 25, + "n_recovered": 25, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 25.520731091469347, + "median_sde_noise": 6.570467023129993, + "per_lc": [ + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004404039587825537, + "SDE": 26.177501702735942, + "chi2_min": 4387.543069049461 + }, + { + "injected": false, + "period": 1.3685027360916138, + "T0": 0.9995278422767413, + "duration": 0.044523872435092926, + "depth": 0.0003865754115395248, + "SDE": 6.356819437068086, + "chi2_min": 4326.839595866841 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.732052489198992, + "duration": 0.21533998847007751, + "depth": 0.004162405151873827, + "SDE": 25.623561478480863, + "chi2_min": 4456.472117348283 + }, + { + "injected": false, + "period": 1.567154884338379, + "T0": 0.6710433548500703, + "duration": 0.046581678092479706, + "depth": 0.0004660347185563296, + "SDE": 9.811690226985908, + "chi2_min": 4249.244214398832 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004389334935694933, + "SDE": 25.122103186161528, + "chi2_min": 4387.086710296348 + }, + { + "injected": false, + "period": 17.946809768676758, + "T0": 11.771186328499653, + "duration": 0.19984866678714752, + "depth": 0.000686309882439673, + "SDE": 6.695235055383752, + "chi2_min": 4314.305852264322 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004312425851821899, + "SDE": 25.631966539805752, + "chi2_min": 4341.908664728141 + }, + { + "injected": false, + "period": 7.888498306274414, + "T0": 7.531212754637977, + "duration": 0.08388378471136093, + "depth": 0.0007113477913662791, + "SDE": 6.570467023129993, + "chi2_min": 4085.738149098137 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.204982191324234, + "depth": 0.004326025955379009, + "SDE": 26.146999811672558, + "chi2_min": 4431.564516407139 + }, + { + "injected": false, + "period": 1.7248963117599487, + "T0": 0.09257843054204251, + "duration": 0.14293743669986725, + "depth": 0.00026448414428159595, + "SDE": 8.812640097544833, + "chi2_min": 4256.353800798309 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.0044168573804199696, + "SDE": 24.497821119953528, + "chi2_min": 4472.887610904101 + }, + { + "injected": false, + "period": 40.31962203979492, + "T0": 12.79962811146072, + "duration": 0.1850813776254654, + "depth": 0.001074486062861979, + "SDE": 5.672305475883705, + "chi2_min": 4326.760088810315 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004235788248479366, + "SDE": 24.954817970912853, + "chi2_min": 4373.691853085323 + }, + { + "injected": false, + "period": 13.618805885314941, + "T0": 12.353813122829024, + "duration": 0.11110421270132065, + "depth": 0.000906570116057992, + "SDE": 6.260135704065025, + "chi2_min": 4297.932157246619 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004246351309120655, + "SDE": 24.37666636200077, + "chi2_min": 4262.907247088052 + }, + { + "injected": false, + "period": 8.089868545532227, + "T0": 4.885035835718213, + "duration": 0.0888851210474968, + "depth": 0.0007501470972783864, + "SDE": 6.336239682418151, + "chi2_min": 4085.4030426856834 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.00426411023363471, + "SDE": 24.126784966742193, + "chi2_min": 4317.331950603972 + }, + { + "injected": false, + "period": 15.671825408935547, + "T0": 11.628149511437869, + "duration": 0.363585501909256, + "depth": 0.0004864199145231396, + "SDE": 5.5538323507584915, + "chi2_min": 4251.70786210115 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.732052489198992, + "duration": 0.21533998847007751, + "depth": 0.004226861987262964, + "SDE": 25.562998807201637, + "chi2_min": 4253.178250383264 + }, + { + "injected": false, + "period": 2.754897117614746, + "T0": 2.5983700068006783, + "duration": 0.08354046940803528, + "depth": 0.0003899047151207924, + "SDE": 6.612445721876433, + "chi2_min": 4304.2806226586845 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004189441911876202, + "SDE": 25.342519823222744, + "chi2_min": 4441.637445074186 + }, + { + "injected": false, + "period": 7.901713848114014, + "T0": 5.554735825406851, + "duration": 0.10750557482242584, + "depth": 0.0006463858881033957, + "SDE": 6.610492881251317, + "chi2_min": 4282.332309697514 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004312783945351839, + "SDE": 25.520731091469347, + "chi2_min": 4257.315695769827 + }, + { + "injected": false, + "period": 2.0137128829956055, + "T0": 1.3472117866492113, + "duration": 0.05591322481632233, + "depth": 0.000497570086736232, + "SDE": 10.587910496607027, + "chi2_min": 4280.768136245288 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7128754423422947, + "duration": 0.2263185828924179, + "depth": 0.004149800632148981, + "SDE": 25.510778485710183, + "chi2_min": 4445.6471137767185 + }, + { + "injected": false, + "period": 14.453306198120117, + "T0": 7.792941111104028, + "duration": 0.23816171288490295, + "depth": 0.0005341128562577069, + "SDE": 5.291739440555412, + "chi2_min": 4100.002558732529 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.0041998703964054585, + "SDE": 26.34910531242964, + "chi2_min": 4507.700801853651 + }, + { + "injected": false, + "period": 10.265218734741211, + "T0": 3.1706764167317942, + "duration": 0.09158045053482056, + "depth": 0.0007960263756103814, + "SDE": 8.393836683396165, + "chi2_min": 4252.540272747918 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004519070964306593, + "SDE": 24.893549086341817, + "chi2_min": 4459.222228646795 + }, + { + "injected": false, + "period": 30.56487464904785, + "T0": 7.08230056832997, + "duration": 0.12538689374923706, + "depth": 0.0011783387744799256, + "SDE": 6.166500977316034, + "chi2_min": 4209.062413090763 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004347286187112331, + "SDE": 25.645459284219083, + "chi2_min": 4367.650080260724 + }, + { + "injected": false, + "period": 36.307926177978516, + "T0": 19.91623931560639, + "duration": 0.29323291778564453, + "depth": 0.0009722203249111772, + "SDE": 5.961172666064783, + "chi2_min": 4425.980193094114 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.0043581826612353325, + "SDE": 25.620072108700576, + "chi2_min": 4418.55047630803 + }, + { + "injected": false, + "period": 3.8394787311553955, + "T0": 3.5170847570018395, + "duration": 0.08451777696609497, + "depth": 0.0004938149941153824, + "SDE": 7.286316523814045, + "chi2_min": 4251.628013641141 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7056692181227504, + "duration": 0.2263185828924179, + "depth": 0.003965914715081453, + "SDE": 26.83157990977236, + "chi2_min": 4355.02648468021 + }, + { + "injected": false, + "period": 1.1502342224121094, + "T0": 0.1958829591745257, + "duration": 0.04874681308865547, + "depth": 0.0003573001886252314, + "SDE": 6.8037354352473, + "chi2_min": 4534.605633556768 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004336000885814428, + "SDE": 26.782616306883728, + "chi2_min": 4509.665909110085 + }, + { + "injected": false, + "period": 5.259787082672119, + "T0": 1.6857420942828583, + "duration": 0.08501768857240677, + "depth": 0.0005589709035120904, + "SDE": 6.523270780656528, + "chi2_min": 4316.4516532573625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.0044480483047664165, + "SDE": 25.552776261980224, + "chi2_min": 4414.776178403963 + }, + { + "injected": false, + "period": 14.582316398620605, + "T0": 8.464501963214104, + "duration": 0.08873925358057022, + "depth": 0.001034076907671988, + "SDE": 6.749566604524634, + "chi2_min": 4359.509288619014 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004289723001420498, + "SDE": 25.876474909413623, + "chi2_min": 4506.705052521887 + }, + { + "injected": false, + "period": 12.45097541809082, + "T0": 9.849355446693153, + "duration": 0.13812200725078583, + "depth": 0.0008029531454667449, + "SDE": 7.419173008465264, + "chi2_min": 4300.465232424514 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.7385776951641674, + "duration": 0.21533998847007751, + "depth": 0.004041068255901337, + "SDE": 25.209039951602133, + "chi2_min": 4325.576950239149 + }, + { + "injected": false, + "period": 2.9074718952178955, + "T0": 1.8813054051288134, + "duration": 0.07331513613462448, + "depth": 0.00043522383202798665, + "SDE": 5.477008302567191, + "chi2_min": 4107.6394164915755 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004308898001909256, + "SDE": 25.054476910642528, + "chi2_min": 4555.486684237196 + }, + { + "injected": false, + "period": 3.8546807765960693, + "T0": 3.842780059564987, + "duration": 0.20632818341255188, + "depth": 0.0003478149010334164, + "SDE": 5.267234453913335, + "chi2_min": 4368.599291771086 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.732052489198992, + "duration": 0.21533998847007751, + "depth": 0.004108169581741095, + "SDE": 24.629152402589423, + "chi2_min": 4430.720853986382 + }, + { + "injected": false, + "period": 5.158578872680664, + "T0": 1.2311123437995661, + "duration": 0.10296858102083206, + "depth": 0.0004856034356635064, + "SDE": 7.478173387504096, + "chi2_min": 4369.114303804741 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.204982191324234, + "depth": 0.004322155378758907, + "SDE": 25.02897262869357, + "chi2_min": 4547.568737473479 + }, + { + "injected": false, + "period": 1.5529592037200928, + "T0": 1.0412210721013935, + "duration": 0.09288113564252853, + "depth": 0.00030092347878962755, + "SDE": 5.96437632528338, + "chi2_min": 4323.484146598777 + } + ] + } + } + }, + "tess-2min": { + "config": { + "ndata": 19710, + "baseline": 27.4, + "cadence": 0.001388888888888889, + "noise": 0.002, + "inject_period": 7.7, + "inject_depth": 0.005, + "period_min": 0.6, + "period_max": 13.7, + "nlc": 50 + }, + "nlc": 50, + "nperiods": 2497, + "impls": { + "new": { + "nlc": 50, + "total_s": 0.1409610400442034, + "times_s": [ + 0.1409610400442034 + ], + "ms_per_lc": 2.819220800884068, + "lc_per_s": 354.70793904699275, + "n_injected": 25, + "n_recovered": 25, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.745711407566798, + "median_sde_noise": 5.684664617948238, + "per_lc": [ + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005485764238983393, + "SDE": 14.639897918026437, + "chi2_min": 19986.645856211093 + }, + { + "injected": false, + "period": 13.100994110107422, + "T0": 5.437705039673006, + "duration": 0.10437987744808197, + "depth": 0.00097375811310485, + "SDE": 6.51029884384331, + "chi2_min": 19991.359227174664 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005453883670270443, + "SDE": 14.01951975362099, + "chi2_min": 20026.577512524516 + }, + { + "injected": false, + "period": 0.727395236492157, + "T0": 0.3019376498355886, + "duration": 0.0418415404856205, + "depth": 0.0003676938358694315, + "SDE": 5.684664617948238, + "chi2_min": 19321.845612071113 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.00540515873581171, + "SDE": 14.726376767600666, + "chi2_min": 19669.763819709846 + }, + { + "injected": false, + "period": 2.640021324157715, + "T0": 0.4917686880570642, + "duration": 0.07459784299135208, + "depth": 0.0004884963855147362, + "SDE": 6.6571320597978705, + "chi2_min": 19593.49303085074 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005405776668339968, + "SDE": 14.777059905804203, + "chi2_min": 19828.85640417305 + }, + { + "injected": false, + "period": 9.231582641601562, + "T0": 1.668764258751935, + "duration": 0.07619598507881165, + "depth": 0.0008226633653976023, + "SDE": 4.722181891853178, + "chi2_min": 20048.86317008199 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005362111143767834, + "SDE": 14.354143808352125, + "chi2_min": 19451.406444908673 + }, + { + "injected": false, + "period": 1.5595471858978271, + "T0": 0.281584903400649, + "duration": 0.06259265542030334, + "depth": 0.00037873227847740054, + "SDE": 5.943673964398746, + "chi2_min": 19451.819498490713 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005432446021586657, + "SDE": 14.968046777015651, + "chi2_min": 19835.65647686846 + }, + { + "injected": false, + "period": 3.7597527503967285, + "T0": 3.551468894538374, + "duration": 0.09266479313373566, + "depth": 0.0005465572467073798, + "SDE": 4.939380282163157, + "chi2_min": 19562.21720545303 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005425633862614632, + "SDE": 14.533890807013856, + "chi2_min": 19661.441555852696 + }, + { + "injected": false, + "period": 5.938205242156982, + "T0": 1.8585079530804478, + "duration": 0.0977407768368721, + "depth": 0.0006803313735872507, + "SDE": 5.2725429446240595, + "chi2_min": 19645.717433759728 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005327630788087845, + "SDE": 14.84010498188191, + "chi2_min": 19854.839841139597 + }, + { + "injected": false, + "period": 0.6239511370658875, + "T0": 0.1721244509631692, + "duration": 0.03426845371723175, + "depth": 0.0003540570323821157, + "SDE": 6.394813243780807, + "chi2_min": 19814.719961456234 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005372271407395601, + "SDE": 14.723770552185087, + "chi2_min": 19759.874102802845 + }, + { + "injected": false, + "period": 1.7957980632781982, + "T0": 0.0708701585838174, + "duration": 0.048745013773441315, + "depth": 0.00045976031105965376, + "SDE": 6.211765916081824, + "chi2_min": 19886.988311534038 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005604728125035763, + "SDE": 14.90068399024373, + "chi2_min": 19847.307987816148 + }, + { + "injected": false, + "period": 1.7158273458480835, + "T0": 0.7042438654324634, + "duration": 0.04801042377948761, + "depth": 0.0004377198056317866, + "SDE": 4.988946210902911, + "chi2_min": 19686.281949983317 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005634222645312548, + "SDE": 15.213471098874043, + "chi2_min": 20082.62622246992 + }, + { + "injected": false, + "period": 1.944218635559082, + "T0": 1.0748527127935859, + "duration": 0.04533376544713974, + "depth": 0.0005116008687764406, + "SDE": 5.995294257451506, + "chi2_min": 19728.37795666568 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005626666825264692, + "SDE": 14.850588900732845, + "chi2_min": 19887.365185557555 + }, + { + "injected": false, + "period": 5.338284969329834, + "T0": 1.2329951883274148, + "duration": 0.2083013355731964, + "depth": 0.0004553081525955349, + "SDE": 5.2985176588408684, + "chi2_min": 19457.346986131895 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005390736740082502, + "SDE": 14.700392737248483, + "chi2_min": 19622.466311638673 + }, + { + "injected": false, + "period": 1.9001942873001099, + "T0": 1.6714522132299692, + "duration": 0.16299022734165192, + "depth": 0.0003048948128707707, + "SDE": 6.331010289372725, + "chi2_min": 19683.71679549537 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0052563706412911415, + "SDE": 14.6409129125974, + "chi2_min": 19651.33208119841 + }, + { + "injected": false, + "period": 2.132042646408081, + "T0": 1.8807319745508266, + "duration": 0.051615022122859955, + "depth": 0.0005292857531458139, + "SDE": 5.194728043439782, + "chi2_min": 19577.79985606737 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005402364302426577, + "SDE": 14.456168855601687, + "chi2_min": 19436.729586657333 + }, + { + "injected": false, + "period": 2.430079221725464, + "T0": 2.2736688394607825, + "duration": 0.11330521106719971, + "depth": 0.0004198209207970649, + "SDE": 6.671596328367839, + "chi2_min": 19901.711850304608 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005152017343789339, + "SDE": 14.03824231166757, + "chi2_min": 20221.619944051825 + }, + { + "injected": false, + "period": 9.231582641601562, + "T0": 3.019791075150806, + "duration": 0.07619598507881165, + "depth": 0.0008931891061365604, + "SDE": 5.574140967715965, + "chi2_min": 19451.45299624408 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005317769479006529, + "SDE": 15.08019479384714, + "chi2_min": 19643.599153703726 + }, + { + "injected": false, + "period": 8.733040809631348, + "T0": 1.2241375973440398, + "duration": 0.07479896396398544, + "depth": 0.0009044561302289367, + "SDE": 5.23786999611775, + "chi2_min": 19883.518882539494 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005483759101480246, + "SDE": 14.86514059054868, + "chi2_min": 19639.472178093947 + }, + { + "injected": false, + "period": 1.0538432598114014, + "T0": 0.844823486495514, + "duration": 0.05492657795548439, + "depth": 0.0003412514925003052, + "SDE": 7.413836817207922, + "chi2_min": 19181.17701679314 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005476575344800949, + "SDE": 14.959634171354576, + "chi2_min": 19795.391763729953 + }, + { + "injected": false, + "period": 1.7158273458480835, + "T0": 1.437746418930118, + "duration": 0.07496435195207596, + "depth": 0.00039721315260976553, + "SDE": 7.340803590611788, + "chi2_min": 19453.765267702773 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0053500221110880375, + "SDE": 14.900270608006013, + "chi2_min": 20215.64466906669 + }, + { + "injected": false, + "period": 9.213768005371094, + "T0": 3.8128516220795063, + "duration": 0.07614698261022568, + "depth": 0.0008834492764435709, + "SDE": 5.369271320042039, + "chi2_min": 19582.097059867356 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005436438601464033, + "SDE": 15.008995156381834, + "chi2_min": 19810.99344150698 + }, + { + "injected": false, + "period": 1.186469316482544, + "T0": 0.4394331011325221, + "duration": 0.06308804452419281, + "depth": 0.0003383326402399689, + "SDE": 4.907890099364573, + "chi2_min": 19782.61215164576 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005494052078574896, + "SDE": 14.948855903371246, + "chi2_min": 19692.064174238843 + }, + { + "injected": false, + "period": 1.7699131965637207, + "T0": 1.468044076797554, + "duration": 0.04850965365767479, + "depth": 0.0005157210398465395, + "SDE": 6.399392674323263, + "chi2_min": 19890.123616665805 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005343742202967405, + "SDE": 14.745711407566798, + "chi2_min": 19796.72417997518 + }, + { + "injected": false, + "period": 1.6712085008621216, + "T0": 0.23874408222442334, + "duration": 0.05521129071712494, + "depth": 0.00045216272701509297, + "SDE": 6.500801607297511, + "chi2_min": 19370.162059362396 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005551040638238192, + "SDE": 14.71396727997725, + "chi2_min": 19685.802620606155 + }, + { + "injected": false, + "period": 0.9706023335456848, + "T0": 0.9548758508475785, + "duration": 0.07941237837076187, + "depth": 0.000291008735075593, + "SDE": 5.375327682145727, + "chi2_min": 20024.64889769606 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005364943295717239, + "SDE": 14.324658514335809, + "chi2_min": 19449.195780767288 + }, + { + "injected": false, + "period": 3.3878562450408936, + "T0": 2.2401032092012088, + "duration": 0.06023088097572327, + "depth": 0.0006338467355817556, + "SDE": 5.240741638867381, + "chi2_min": 19773.893695076826 + } + ] + } + } + }, + "tess-yr": { + "config": { + "ndata": 16850, + "baseline": 351.0, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 21.7, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 175.0, + "nlc": 20 + }, + "nlc": 20, + "nperiods": 42001, + "impls": { + "new": { + "nlc": 20, + "total_s": 0.3685928500490263, + "times_s": [ + 0.3685928500490263 + ], + "ms_per_lc": 18.429642502451316, + "lc_per_s": 54.260412260682244, + "n_injected": 10, + "n_recovered": 10, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 52.45753681269514, + "median_sde_noise": 8.462352256235231, + "per_lc": [ + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.00428521353751421, + "SDE": 51.74706350296344, + "chi2_min": 17045.304161600427 + }, + { + "injected": false, + "period": 71.1637191772461, + "T0": 34.1104773348261, + "duration": 0.19279845058918, + "depth": 0.0008943733409978449, + "SDE": 8.028487044071968, + "chi2_min": 16855.451608264993 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004315289203077555, + "SDE": 53.5792260804763, + "chi2_min": 17079.369669986347 + }, + { + "injected": false, + "period": 3.215691566467285, + "T0": 2.7022411507869606, + "duration": 0.05919283628463745, + "depth": 0.00034801653237082064, + "SDE": 6.9967664700766345, + "chi2_min": 16563.562434798696 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004378140438348055, + "SDE": 51.41700284707218, + "chi2_min": 16690.807726532905 + }, + { + "injected": false, + "period": 1.5765894651412964, + "T0": 1.1244638781501877, + "duration": 0.046674944460392, + "depth": 0.00028764992021024227, + "SDE": 9.104482354902814, + "chi2_min": 16943.34078928957 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004271374084055424, + "SDE": 53.34992640941852, + "chi2_min": 16960.625747997896 + }, + { + "injected": false, + "period": 13.20435905456543, + "T0": 1.339143794434733, + "duration": 0.2093072384595871, + "depth": 0.00039136491250246763, + "SDE": 8.470054948457452, + "chi2_min": 16618.206479002816 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004417836666107178, + "SDE": 52.79030624710437, + "chi2_min": 17073.47447652764 + }, + { + "injected": false, + "period": 1.0810301303863525, + "T0": 0.8323784887314218, + "duration": 0.03727799281477928, + "depth": 0.00030446742312051356, + "SDE": 12.367130312287468, + "chi2_min": 16803.589990291133 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.0041633895598351955, + "SDE": 51.30555986400533, + "chi2_min": 17136.81803806736 + }, + { + "injected": false, + "period": 35.858131408691406, + "T0": 3.57559711400188, + "duration": 0.30683863162994385, + "depth": 0.0005235545104369521, + "SDE": 7.264360808610101, + "chi2_min": 16644.461869314277 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.0043487101793289185, + "SDE": 53.18143500109468, + "chi2_min": 17383.538593224726 + }, + { + "injected": false, + "period": 1.4476821422576904, + "T0": 1.3089501248304032, + "duration": 0.04536651819944382, + "depth": 0.00027384364511817694, + "SDE": 8.454649564013012, + "chi2_min": 17168.875156750462 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.0043377201072871685, + "SDE": 52.12476737828592, + "chi2_min": 17070.551816905958 + }, + { + "injected": false, + "period": 158.73745727539062, + "T0": 94.37186024718721, + "duration": 0.3933356702327728, + "depth": 0.0010018610628321767, + "SDE": 7.243525177058378, + "chi2_min": 16733.71459318848 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004398010671138763, + "SDE": 52.85238242983881, + "chi2_min": 17030.781448475514 + }, + { + "injected": false, + "period": 143.65647888183594, + "T0": 105.68818444369845, + "duration": 0.23189450800418854, + "depth": 0.0014297961024567485, + "SDE": 9.032557767575465, + "chi2_min": 16928.81373207052 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004301433917135, + "SDE": 50.820057611926856, + "chi2_min": 16781.757778621162 + }, + { + "injected": false, + "period": 1.0684576034545898, + "T0": 0.9389372063940868, + "duration": 0.04099807143211365, + "depth": 0.000271445867838338, + "SDE": 9.54321175516312, + "chi2_min": 16826.68702423067 + } + ] + } + } + }, + "kepler-4yr": { + "config": { + "ndata": 65440, + "baseline": 1363.0, + "cadence": 0.020833333333333332, + "noise": 0.0006, + "inject_period": 41.3, + "inject_depth": 0.003, + "period_min": 0.6, + "period_max": 500.0, + "nlc": 10 + }, + "nlc": 10, + "nperiods": 171688, + "impls": { + "new": { + "nlc": 10, + "total_s": 1.6760276049608365, + "times_s": [ + 1.6760276049608365 + ], + "ms_per_lc": 167.60276049608365, + "lc_per_s": 5.966488839683323, + "n_injected": 5, + "n_recovered": 5, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 98.29821370846379, + "median_sde_noise": 8.722158471115197, + "per_lc": [ + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003353167325258255, + "SDE": 98.45695586534704, + "chi2_min": 65888.8686123984 + }, + { + "injected": false, + "period": 55.92778396606445, + "T0": 50.19175134709553, + "duration": 0.16932636499404907, + "depth": 0.0003138199681416154, + "SDE": 8.722158471115197, + "chi2_min": 65560.97205817862 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003339726710692048, + "SDE": 100.12524704417672, + "chi2_min": 66294.66735087954 + }, + { + "injected": false, + "period": 131.69247436523438, + "T0": 60.8605908603713, + "duration": 0.20403198897838593, + "depth": 0.0004167061997577548, + "SDE": 8.661975684684567, + "chi2_min": 65907.71342974457 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0033489372581243515, + "SDE": 97.03154092729665, + "chi2_min": 66182.91527186599 + }, + { + "injected": false, + "period": 96.05792236328125, + "T0": 50.60741073171448, + "duration": 0.2130729854106903, + "depth": 0.00037875358248129487, + "SDE": 11.123223491414974, + "chi2_min": 65325.414736351566 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003390850266441703, + "SDE": 98.0194282869755, + "chi2_min": 66280.838278687 + }, + { + "injected": false, + "period": 164.4737091064453, + "T0": 46.597844866974356, + "duration": 0.23087593913078308, + "depth": 0.0004218894464429468, + "SDE": 7.961574440597722, + "chi2_min": 65834.8010161592 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0033445751760154963, + "SDE": 98.29821370846379, + "chi2_min": 66655.12926137832 + }, + { + "injected": false, + "period": 2.184530735015869, + "T0": 1.3664060570654044, + "duration": 0.10407035797834396, + "depth": 7.64523065299727e-05, + "SDE": 9.621362334057467, + "chi2_min": 65125.09877587645 + } + ] + } + } + } + }, + "env": { + "python": "3.11.10", + "numpy": "2.4.6", + "hostname": "b09d596f0cce", + "cpu_count": 64, + "cuvarbase": "1.0.0", + "pycuda": "2026.1", + "cuda_driver_version": 13000, + "gpu": "NVIDIA RTX A5000", + "compute_capability": "8.6", + "nvcc": "Cuda compilation tools, release 12.4, V12.4.131" + } +} \ No newline at end of file diff --git a/benchmarks/results/tls_survey_jul2026/tls_survey_rtx4000ada.json b/benchmarks/results/tls_survey_jul2026/tls_survey_rtx4000ada.json new file mode 100644 index 0000000..60f9aca --- /dev/null +++ b/benchmarks/results/tls_survey_jul2026/tls_survey_rtx4000ada.json @@ -0,0 +1,2269 @@ +{ + "script": "benchmark_tls_survey.py", + "timestamp": "2026-07-06T18:12:17", + "args": { + "regimes": "tess-ffi,k2,tess-2min,tess-yr,kepler-4yr", + "nlc": null, + "impls": "new", + "ref_nlc": 1, + "old_nlc": 5, + "n_iter": 1, + "output": "tls_survey_rtx4000ada.json", + "quick": false, + "ref_all": false + }, + "regimes": { + "tess-ffi": { + "config": { + "ndata": 1310, + "baseline": 27.4, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 7.7, + "inject_depth": 0.005, + "period_min": 0.6, + "period_max": 13.7, + "nlc": 100 + }, + "nlc": 100, + "nperiods": 2486, + "impls": { + "new": { + "nlc": 100, + "total_s": 0.30543674528598785, + "times_s": [ + 0.30543674528598785 + ], + "ms_per_lc": 3.0543674528598785, + "lc_per_s": 327.40003140868845, + "n_injected": 50, + "n_recovered": 50, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.2159561918949, + "median_sde_noise": 5.443089791132511, + "per_lc": [ + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005532108247280121, + "SDE": 14.065390650435956, + "chi2_min": 1336.7557435313201 + }, + { + "injected": false, + "period": 0.6225233674049377, + "T0": 0.542300333010111, + "duration": 0.037806544452905655, + "depth": 0.0005694830324500799, + "SDE": 4.950339285343851, + "chi2_min": 1315.3825465302093 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005046018864959478, + "SDE": 14.353723862800633, + "chi2_min": 1393.1030901098823 + }, + { + "injected": false, + "period": 4.131380081176758, + "T0": 1.2414492021177352, + "duration": 0.06124073639512062, + "depth": 0.00128852017223835, + "SDE": 5.341763809516535, + "chi2_min": 1313.3827822895487 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005532108247280121, + "SDE": 13.579242113724062, + "chi2_min": 1225.935215715939 + }, + { + "injected": false, + "period": 6.83004903793335, + "T0": 3.3232153407358425, + "duration": 0.15217697620391846, + "depth": 0.001029684324748814, + "SDE": 5.390537626148937, + "chi2_min": 1240.1715078378356 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005443227011710405, + "SDE": 14.371898325267232, + "chi2_min": 1269.001673041523 + }, + { + "injected": false, + "period": 1.3832758665084839, + "T0": 1.2062232874457806, + "duration": 0.0404709056019783, + "depth": 0.001005177036859095, + "SDE": 6.775107320253302, + "chi2_min": 1265.1381991709252 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00549427792429924, + "SDE": 14.173016542042589, + "chi2_min": 1249.6949432980077 + }, + { + "injected": false, + "period": 3.7197482585906982, + "T0": 1.5470102355227056, + "duration": 0.08362992107868195, + "depth": 0.0011062233243137598, + "SDE": 4.313070342273851, + "chi2_min": 1306.5296519060553 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00537601625546813, + "SDE": 13.259800800819253, + "chi2_min": 1383.9029934304917 + }, + { + "injected": false, + "period": 3.789888858795166, + "T0": 2.661259939658663, + "duration": 0.06252489984035492, + "depth": 0.001284703379496932, + "SDE": 5.880023046069064, + "chi2_min": 1278.525860381444 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005833111237734556, + "SDE": 14.215403265364708, + "chi2_min": 1307.3178590593716 + }, + { + "injected": false, + "period": 0.694443941116333, + "T0": 0.5409164779852347, + "duration": 0.043291110545396805, + "depth": 0.0007188625750131905, + "SDE": 5.517576909494449, + "chi2_min": 1375.8015752078236 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0054616364650428295, + "SDE": 14.356257153174388, + "chi2_min": 1400.4625896043808 + }, + { + "injected": false, + "period": 0.9697667956352234, + "T0": 0.6234215032222714, + "duration": 0.04170956835150719, + "depth": 0.0007615210488438606, + "SDE": 5.514336641376309, + "chi2_min": 1345.5726786362516 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005138108506798744, + "SDE": 14.9026541561844, + "chi2_min": 1374.5640473015765 + }, + { + "injected": false, + "period": 8.122530937194824, + "T0": 7.832263005316975, + "duration": 0.08061356842517853, + "depth": 0.001534505863673985, + "SDE": 5.392517416890103, + "chi2_min": 1408.3131930415202 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005546618718653917, + "SDE": 14.285447453898277, + "chi2_min": 1320.0360381533574 + }, + { + "injected": false, + "period": 6.6303558349609375, + "T0": 1.8257501173602577, + "duration": 0.09650145471096039, + "depth": 0.0013269108021631837, + "SDE": 6.504767079255062, + "chi2_min": 1293.2735987886438 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0055886139161884785, + "SDE": 14.409292548217513, + "chi2_min": 1236.1293730040288 + }, + { + "injected": false, + "period": 3.265150547027588, + "T0": 1.6735373315951279, + "duration": 0.0594947412610054, + "depth": 0.001139817526564002, + "SDE": 4.939560189166223, + "chi2_min": 1306.6482895325398 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005358264781534672, + "SDE": 14.037121524171635, + "chi2_min": 1378.8564958646666 + }, + { + "injected": false, + "period": 0.9069516062736511, + "T0": 0.4873173068018559, + "duration": 0.04285912215709686, + "depth": 0.0006940899766050279, + "SDE": 7.237230693107558, + "chi2_min": 1326.8709772525024 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005511269439011812, + "SDE": 14.500004810570525, + "chi2_min": 1315.768630715941 + }, + { + "injected": false, + "period": 6.818082332611084, + "T0": 0.19493036610213732, + "duration": 0.06887488067150116, + "depth": 0.001466379500925541, + "SDE": 4.695511534603615, + "chi2_min": 1332.3330495656523 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005003546830266714, + "SDE": 14.708295639901666, + "chi2_min": 1274.4610292007467 + }, + { + "injected": false, + "period": 1.3818519115447998, + "T0": 0.3538014247310741, + "duration": 0.040457021445035934, + "depth": 0.0008182328892871737, + "SDE": 6.284759724974738, + "chi2_min": 1271.7957420160972 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005669730249792337, + "SDE": 15.41197265877213, + "chi2_min": 1376.2414849254828 + }, + { + "injected": false, + "period": 9.743551254272461, + "T0": 5.753463031568231, + "duration": 0.09000206738710403, + "depth": 0.0015667054103687406, + "SDE": 5.3858364105068715, + "chi2_min": 1213.2532298462943 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.18374329805374146, + "depth": 0.005207412876188755, + "SDE": 14.868149544133214, + "chi2_min": 1277.8260611819942 + }, + { + "injected": false, + "period": 3.751904010772705, + "T0": 3.4951949631796992, + "duration": 0.05644047260284424, + "depth": 0.0012609766563400626, + "SDE": 4.929817836339992, + "chi2_min": 1313.6198509818798 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.18374329805374146, + "depth": 0.004843113943934441, + "SDE": 14.536503086957408, + "chi2_min": 1386.7924769026886 + }, + { + "injected": false, + "period": 12.579136848449707, + "T0": 4.226824228778526, + "duration": 0.12552805244922638, + "depth": 0.0016740263672545552, + "SDE": 5.493662165374919, + "chi2_min": 1264.473948842068 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.004762181080877781, + "SDE": 14.148837331556905, + "chi2_min": 1356.2967423676214 + }, + { + "injected": false, + "period": 2.6725428104400635, + "T0": 0.14387011199786048, + "duration": 0.05565265938639641, + "depth": 0.0010715341195464134, + "SDE": 6.350914315973196, + "chi2_min": 1289.7367575326448 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005513254553079605, + "SDE": 14.373714227286166, + "chi2_min": 1438.3267171983498 + }, + { + "injected": false, + "period": 0.6743714809417725, + "T0": 0.47082369012325387, + "duration": 0.038828302174806595, + "depth": 0.0007056446629576385, + "SDE": 6.976825853970327, + "chi2_min": 1296.7100488048077 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005650545936077833, + "SDE": 15.005956603817001, + "chi2_min": 1335.367667329123 + }, + { + "injected": false, + "period": 3.817335605621338, + "T0": 0.3609841388095205, + "duration": 0.06267549097537994, + "depth": 0.0010340978624299169, + "SDE": 5.272298829267682, + "chi2_min": 1315.3716891212723 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005670913495123386, + "SDE": 14.08645398117616, + "chi2_min": 1247.6468554586909 + }, + { + "injected": false, + "period": 8.94373893737793, + "T0": 4.204453678020741, + "duration": 0.07539563626050949, + "depth": 0.0017777406610548496, + "SDE": 4.767810978884853, + "chi2_min": 1302.41173783788 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005472847260534763, + "SDE": 14.711449416620528, + "chi2_min": 1300.7378989330853 + }, + { + "injected": false, + "period": 1.083532452583313, + "T0": 0.43690821784262823, + "duration": 0.05275972932577133, + "depth": 0.0006725414423272014, + "SDE": 5.844557826021007, + "chi2_min": 1303.3270971047903 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005429901648312807, + "SDE": 13.581099031295597, + "chi2_min": 1338.4324806558413 + }, + { + "injected": false, + "period": 3.751904010772705, + "T0": 1.6210399439368501, + "duration": 0.05644047260284424, + "depth": 0.0013095358153805137, + "SDE": 4.52067456400783, + "chi2_min": 1327.7450767907026 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005096363835036755, + "SDE": 13.503372276972755, + "chi2_min": 1241.699730173737 + }, + { + "injected": false, + "period": 5.536378383636475, + "T0": 2.694534725723358, + "duration": 0.07094460725784302, + "depth": 0.0013462472707033157, + "SDE": 4.509943163563067, + "chi2_min": 1267.498920703772 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005140651483088732, + "SDE": 14.075288228225297, + "chi2_min": 1313.3261367914786 + }, + { + "injected": false, + "period": 9.36865520477295, + "T0": 9.22744536080586, + "duration": 0.1387048214673996, + "depth": 0.0016929280245676637, + "SDE": 6.098590225698274, + "chi2_min": 1253.9192065986254 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005635196343064308, + "SDE": 14.216509118425094, + "chi2_min": 1322.711499255337 + }, + { + "injected": false, + "period": 0.8091202974319458, + "T0": 0.4492196189062554, + "duration": 0.04125908017158508, + "depth": 0.0006857021362520754, + "SDE": 5.7191670355570885, + "chi2_min": 1371.571016880274 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.18374329805374146, + "depth": 0.005087862256914377, + "SDE": 13.784317299008805, + "chi2_min": 1289.7056162390122 + }, + { + "injected": false, + "period": 0.8660217523574829, + "T0": 0.2383568104642464, + "duration": 0.06924357265233994, + "depth": 0.000580215360969305, + "SDE": 6.840602631288061, + "chi2_min": 1302.0461920367197 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005201755557209253, + "SDE": 14.966413216209395, + "chi2_min": 1310.6803436341113 + }, + { + "injected": false, + "period": 6.253728866577148, + "T0": 5.870805941826802, + "duration": 0.07388520240783691, + "depth": 0.0012998866150155663, + "SDE": 5.263553605921748, + "chi2_min": 1209.4973824857957 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005448559299111366, + "SDE": 13.623365131240881, + "chi2_min": 1390.4382307294914 + }, + { + "injected": false, + "period": 12.104578018188477, + "T0": 9.877395361733647, + "duration": 0.09207913279533386, + "depth": 0.001985683338716626, + "SDE": 5.286761852211583, + "chi2_min": 1289.7191295226003 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.005371253006160259, + "SDE": 14.089673680989746, + "chi2_min": 1326.8539697531978 + }, + { + "injected": false, + "period": 1.4328784942626953, + "T0": 1.2479081935049408, + "duration": 0.04094899445772171, + "depth": 0.0009649074636399746, + "SDE": 6.146771193677066, + "chi2_min": 1376.8769192147242 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005038459785282612, + "SDE": 14.131821472224129, + "chi2_min": 1418.7284940720592 + }, + { + "injected": false, + "period": 2.585336923599243, + "T0": 0.923334637585171, + "duration": 0.13419054448604584, + "depth": 0.0006379721453413367, + "SDE": 5.255854439678939, + "chi2_min": 1297.9203697652006 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0051691848784685135, + "SDE": 14.53686084600899, + "chi2_min": 1335.154218438021 + }, + { + "injected": false, + "period": 1.1863054037094116, + "T0": 0.5719344635827, + "duration": 0.04040246084332466, + "depth": 0.000764436786994338, + "SDE": 4.7496092994714445, + "chi2_min": 1279.015192561413 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0054274569265544415, + "SDE": 13.665247925323182, + "chi2_min": 1318.2331768535635 + }, + { + "injected": false, + "period": 2.7281653881073, + "T0": 1.4686617796954948, + "duration": 0.06830879300832748, + "depth": 0.0009055134141817689, + "SDE": 5.017593764460343, + "chi2_min": 1256.61867619463 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005423026625066996, + "SDE": 13.104268255806913, + "chi2_min": 1284.7775721516596 + }, + { + "injected": false, + "period": 4.76552152633667, + "T0": 1.076287644484374, + "duration": 0.06748615950345993, + "depth": 0.001369902165606618, + "SDE": 5.838514395192009, + "chi2_min": 1268.924454853593 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005303625948727131, + "SDE": 13.768917687037854, + "chi2_min": 1469.3855329483195 + }, + { + "injected": false, + "period": 5.954711437225342, + "T0": 4.0025587667688, + "duration": 0.06583552062511444, + "depth": 0.0015804474242031574, + "SDE": 4.620174626379325, + "chi2_min": 1338.3957556418723 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3166635296710325, + "duration": 0.17486760020256042, + "depth": 0.00547246215865016, + "SDE": 13.970445375123868, + "chi2_min": 1231.4136864085472 + }, + { + "injected": false, + "period": 0.7494922876358032, + "T0": 0.14383159056938233, + "duration": 0.06598714739084244, + "depth": 0.00045808343566022813, + "SDE": 5.954589818857165, + "chi2_min": 1183.9089290347831 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005119277164340019, + "SDE": 13.600633570914596, + "chi2_min": 1362.5470870930055 + }, + { + "injected": false, + "period": 2.8218910694122314, + "T0": 0.3113438265453894, + "duration": 0.07258859276771545, + "depth": 0.0010486793471500278, + "SDE": 6.400880360273832, + "chi2_min": 1301.5649681369214 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005257221404463053, + "SDE": 14.531584442008283, + "chi2_min": 1288.7046099807844 + }, + { + "injected": false, + "period": 7.533771991729736, + "T0": 2.4072671396336887, + "duration": 0.07120505720376968, + "depth": 0.0016296235844492912, + "SDE": 5.648052966355431, + "chi2_min": 1290.2735534736444 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005214043892920017, + "SDE": 13.501816275269112, + "chi2_min": 1333.4523123305858 + }, + { + "injected": false, + "period": 2.045438051223755, + "T0": 0.19033353368033445, + "duration": 0.04844745248556137, + "depth": 0.0009628356783650815, + "SDE": 5.736909643733822, + "chi2_min": 1390.8257634245467 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.302647882457407, + "duration": 0.19306959211826324, + "depth": 0.005054534412920475, + "SDE": 13.52684222988886, + "chi2_min": 1318.2392164019288 + }, + { + "injected": false, + "period": 9.047518730163574, + "T0": 4.986207971831902, + "duration": 0.12417609244585037, + "depth": 0.0012691774172708392, + "SDE": 5.130269511847086, + "chi2_min": 1229.019885531746 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.005109364632517099, + "SDE": 15.091514124837634, + "chi2_min": 1269.2879464986113 + }, + { + "injected": false, + "period": 4.433368682861328, + "T0": 3.8600783631616196, + "duration": 0.059669382870197296, + "depth": 0.0014127626782283187, + "SDE": 5.318909711833129, + "chi2_min": 1282.9852399707484 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00571216456592083, + "SDE": 13.68735144752792, + "chi2_min": 1391.5502979665098 + }, + { + "injected": false, + "period": 3.42227840423584, + "T0": 1.513876878042396, + "duration": 0.05473672226071358, + "depth": 0.0012891065562143922, + "SDE": 5.639916284783208, + "chi2_min": 1319.0337806769976 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005534767638891935, + "SDE": 14.290255163436195, + "chi2_min": 1310.234607494101 + }, + { + "injected": false, + "period": 13.635416984558105, + "T0": 4.660816806064474, + "duration": 0.1823594868183136, + "depth": 0.001385409850627184, + "SDE": 5.697635676846859, + "chi2_min": 1203.2160460078271 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005357676651328802, + "SDE": 13.642723226547098, + "chi2_min": 1339.592726568851 + }, + { + "injected": false, + "period": 12.15611457824707, + "T0": 4.847994174497785, + "duration": 0.15128548443317413, + "depth": 0.0013391552492976189, + "SDE": 5.1152540651708565, + "chi2_min": 1278.6733893042583 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0052889143116772175, + "SDE": 14.59080489843393, + "chi2_min": 1395.672670674071 + }, + { + "injected": false, + "period": 9.978133201599121, + "T0": 3.989828930425375, + "duration": 0.23240043222904205, + "depth": 0.001154838944785297, + "SDE": 6.614594176237315, + "chi2_min": 1311.4876419213956 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0054702446796, + "SDE": 13.901584845266553, + "chi2_min": 1303.8109990226483 + }, + { + "injected": false, + "period": 1.227888584136963, + "T0": 0.24339220282239182, + "duration": 0.06381379067897797, + "depth": 0.0007502195076085627, + "SDE": 6.699391970724505, + "chi2_min": 1254.5677523085624 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0049850489012897015, + "SDE": 14.549175594439973, + "chi2_min": 1355.400272127356 + }, + { + "injected": false, + "period": 2.2177605628967285, + "T0": 1.0043958503840145, + "duration": 0.06375162303447723, + "depth": 0.0008952956413850188, + "SDE": 5.1197930532229785, + "chi2_min": 1339.4699305699805 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.308795390041496, + "duration": 0.19306959211826324, + "depth": 0.004980760160833597, + "SDE": 14.525513225084268, + "chi2_min": 1379.7126956069637 + }, + { + "injected": false, + "period": 3.958618640899658, + "T0": 1.5509364717303242, + "duration": 0.0574585385620594, + "depth": 0.0012683860259130597, + "SDE": 4.945356782284237, + "chi2_min": 1282.2177474202194 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005414358805865049, + "SDE": 15.565120663517906, + "chi2_min": 1338.7585082855128 + }, + { + "injected": false, + "period": 12.286243438720703, + "T0": 0.6104409236496622, + "duration": 0.08381339907646179, + "depth": 0.0018242186633870006, + "SDE": 6.411775304695559, + "chi2_min": 1332.7316477155935 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005437161773443222, + "SDE": 15.014119449786673, + "chi2_min": 1358.6656671348069 + }, + { + "injected": false, + "period": 6.318080902099609, + "T0": 0.0469745786837219, + "duration": 0.06714829802513123, + "depth": 0.0013039918849244714, + "SDE": 4.801564872948044, + "chi2_min": 1247.8763909035313 + } + ] + } + } + }, + "k2": { + "config": { + "ndata": 4320, + "baseline": 90.0, + "cadence": 0.020833333333333332, + "noise": 0.0008, + "inject_period": 12.4, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 45.0, + "nlc": 50 + }, + "nlc": 50, + "nperiods": 9672, + "impls": { + "new": { + "nlc": 50, + "total_s": 0.32082032412290573, + "times_s": [ + 0.32082032412290573 + ], + "ms_per_lc": 6.416406482458115, + "lc_per_s": 155.85047529858204, + "n_injected": 25, + "n_recovered": 25, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 25.520731137419894, + "median_sde_noise": 6.570467023158963, + "per_lc": [ + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004404039587825537, + "SDE": 26.17749702404464, + "chi2_min": 4387.543069049461 + }, + { + "injected": false, + "period": 1.3685027360916138, + "T0": 0.9995278422767413, + "duration": 0.044523872435092926, + "depth": 0.0003865754115395248, + "SDE": 6.356818574676183, + "chi2_min": 4326.839595866841 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.732052489198992, + "duration": 0.21533998847007751, + "depth": 0.004162405151873827, + "SDE": 25.62356163529343, + "chi2_min": 4456.472117348283 + }, + { + "injected": false, + "period": 1.567154884338379, + "T0": 0.6710433548500703, + "duration": 0.046581678092479706, + "depth": 0.0004660347185563296, + "SDE": 9.811689077322027, + "chi2_min": 4249.244214398832 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004389334935694933, + "SDE": 25.122103240809416, + "chi2_min": 4387.086710296348 + }, + { + "injected": false, + "period": 17.946809768676758, + "T0": 11.771186328499653, + "duration": 0.19984866678714752, + "depth": 0.000686309882439673, + "SDE": 6.69523511064994, + "chi2_min": 4314.305852264322 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004312425851821899, + "SDE": 25.631966697906847, + "chi2_min": 4341.908664728141 + }, + { + "injected": false, + "period": 7.888498306274414, + "T0": 7.531212754637977, + "duration": 0.08388378471136093, + "depth": 0.0007113477913662791, + "SDE": 6.570467023158963, + "chi2_min": 4085.738149098137 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.204982191324234, + "depth": 0.004326025955379009, + "SDE": 26.14699977131388, + "chi2_min": 4431.564516407139 + }, + { + "injected": false, + "period": 1.7248963117599487, + "T0": 0.09257843054204251, + "duration": 0.14293743669986725, + "depth": 0.00026448414428159595, + "SDE": 8.812640088645056, + "chi2_min": 4256.353800798309 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.0044168573804199696, + "SDE": 24.49782119878163, + "chi2_min": 4472.887610904101 + }, + { + "injected": false, + "period": 40.31962203979492, + "T0": 12.79962811146072, + "duration": 0.1850813776254654, + "depth": 0.001074486062861979, + "SDE": 5.6723058332231195, + "chi2_min": 4326.760088810315 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004235788248479366, + "SDE": 24.954817922084917, + "chi2_min": 4373.691853085323 + }, + { + "injected": false, + "period": 13.618805885314941, + "T0": 12.353813122829024, + "duration": 0.11110421270132065, + "depth": 0.000906570116057992, + "SDE": 6.260135732254157, + "chi2_min": 4297.932157246619 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004246351309120655, + "SDE": 24.37666606073983, + "chi2_min": 4262.907247088052 + }, + { + "injected": false, + "period": 8.089868545532227, + "T0": 4.885035835718213, + "duration": 0.0888851210474968, + "depth": 0.0007501470972783864, + "SDE": 6.33623962858502, + "chi2_min": 4085.4030426856834 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.00426411023363471, + "SDE": 24.126784931778023, + "chi2_min": 4317.331950603972 + }, + { + "injected": false, + "period": 15.671825408935547, + "T0": 11.628149511437869, + "duration": 0.363585501909256, + "depth": 0.0004864199145231396, + "SDE": 5.553832261704813, + "chi2_min": 4251.70786210115 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.732052489198992, + "duration": 0.21533998847007751, + "depth": 0.004226861987262964, + "SDE": 25.56299869559361, + "chi2_min": 4253.178250383264 + }, + { + "injected": false, + "period": 2.754897117614746, + "T0": 2.5983700068006783, + "duration": 0.08354046940803528, + "depth": 0.0003899047151207924, + "SDE": 6.612445740904377, + "chi2_min": 4304.2806226586845 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004189441911876202, + "SDE": 25.342519829150696, + "chi2_min": 4441.637445074186 + }, + { + "injected": false, + "period": 7.901713848114014, + "T0": 5.554735825406851, + "duration": 0.10750557482242584, + "depth": 0.0006463858881033957, + "SDE": 6.610492871472095, + "chi2_min": 4282.332309697514 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004312783945351839, + "SDE": 25.520731137419894, + "chi2_min": 4257.315695769827 + }, + { + "injected": false, + "period": 2.0137128829956055, + "T0": 1.3472117866492113, + "duration": 0.05591322481632233, + "depth": 0.000497570086736232, + "SDE": 10.58791051735093, + "chi2_min": 4280.768136245288 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7128754423422947, + "duration": 0.2263185828924179, + "depth": 0.004149800632148981, + "SDE": 25.51077839891597, + "chi2_min": 4445.6471137767185 + }, + { + "injected": false, + "period": 14.453306198120117, + "T0": 7.792941111104028, + "duration": 0.23816171288490295, + "depth": 0.0005341128562577069, + "SDE": 5.291739270813659, + "chi2_min": 4100.002558732529 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.0041998703964054585, + "SDE": 26.349105186230148, + "chi2_min": 4507.700801853651 + }, + { + "injected": false, + "period": 10.265218734741211, + "T0": 3.1706764167317942, + "duration": 0.09158045053482056, + "depth": 0.0007960263756103814, + "SDE": 8.393836638594017, + "chi2_min": 4252.540272747918 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004519070964306593, + "SDE": 24.893549081872777, + "chi2_min": 4459.222228646795 + }, + { + "injected": false, + "period": 30.56487464904785, + "T0": 7.08230056832997, + "duration": 0.12538689374923706, + "depth": 0.0011783387744799256, + "SDE": 6.166500957414006, + "chi2_min": 4209.062413090763 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004347286187112331, + "SDE": 25.645459164761437, + "chi2_min": 4367.650080260724 + }, + { + "injected": false, + "period": 36.307926177978516, + "T0": 19.91623931560639, + "duration": 0.29323291778564453, + "depth": 0.0009722203249111772, + "SDE": 5.96117267411373, + "chi2_min": 4425.980193094114 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.0043581826612353325, + "SDE": 25.620072088535927, + "chi2_min": 4418.55047630803 + }, + { + "injected": false, + "period": 3.8394787311553955, + "T0": 3.5170847570018395, + "duration": 0.08451777696609497, + "depth": 0.0004938149941153824, + "SDE": 7.28631654633567, + "chi2_min": 4251.628013641141 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7056692181227504, + "duration": 0.2263185828924179, + "depth": 0.003965914715081453, + "SDE": 26.83157991532146, + "chi2_min": 4355.02648468021 + }, + { + "injected": false, + "period": 1.1502342224121094, + "T0": 0.1958829591745257, + "duration": 0.04874681308865547, + "depth": 0.0003573001886252314, + "SDE": 6.803735442144992, + "chi2_min": 4534.605633556768 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.004336000885814428, + "SDE": 26.782616254306795, + "chi2_min": 4509.665909110085 + }, + { + "injected": false, + "period": 5.259787082672119, + "T0": 1.6857420942828583, + "duration": 0.08501768857240677, + "depth": 0.0005589709035120904, + "SDE": 6.523270829232497, + "chi2_min": 4316.4516532573625 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.204982191324234, + "depth": 0.0044480483047664165, + "SDE": 25.55277626833395, + "chi2_min": 4414.776178403963 + }, + { + "injected": false, + "period": 14.582316398620605, + "T0": 8.464501963214104, + "duration": 0.08873925358057022, + "depth": 0.001034076907671988, + "SDE": 6.74956661106862, + "chi2_min": 4359.509288619014 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004289723001420498, + "SDE": 25.876474721506405, + "chi2_min": 4506.705052521887 + }, + { + "injected": false, + "period": 12.45097541809082, + "T0": 9.849355446693153, + "duration": 0.13812200725078583, + "depth": 0.0008029531454667449, + "SDE": 7.4191729318083, + "chi2_min": 4300.465232424514 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.7385776951641674, + "duration": 0.21533998847007751, + "depth": 0.004041068255901337, + "SDE": 25.209039859208932, + "chi2_min": 4325.576950239149 + }, + { + "injected": false, + "period": 2.9074718952178955, + "T0": 1.8813054051288134, + "duration": 0.07331513613462448, + "depth": 0.00043522383202798665, + "SDE": 5.477008307447279, + "chi2_min": 4107.6394164915755 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004308898001909256, + "SDE": 25.054476969400678, + "chi2_min": 4555.486684237196 + }, + { + "injected": false, + "period": 3.8546807765960693, + "T0": 3.842780059564987, + "duration": 0.20632818341255188, + "depth": 0.0003478149010334164, + "SDE": 5.267235115169817, + "chi2_min": 4368.599291771086 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.732052489198992, + "duration": 0.21533998847007751, + "depth": 0.004108169581741095, + "SDE": 24.629152760009696, + "chi2_min": 4430.720853986382 + }, + { + "injected": false, + "period": 5.158578872680664, + "T0": 1.2311123437995661, + "duration": 0.10296858102083206, + "depth": 0.0004856034356635064, + "SDE": 7.478173375535206, + "chi2_min": 4369.114303804741 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.204982191324234, + "depth": 0.004322155378758907, + "SDE": 25.028972433845162, + "chi2_min": 4547.568737473479 + }, + { + "injected": false, + "period": 1.5529592037200928, + "T0": 1.0412210721013935, + "duration": 0.09288113564252853, + "depth": 0.00030092347878962755, + "SDE": 5.9643763694597824, + "chi2_min": 4323.484146598777 + } + ] + } + } + }, + "tess-2min": { + "config": { + "ndata": 19710, + "baseline": 27.4, + "cadence": 0.001388888888888889, + "noise": 0.002, + "inject_period": 7.7, + "inject_depth": 0.005, + "period_min": 0.6, + "period_max": 13.7, + "nlc": 50 + }, + "nlc": 50, + "nperiods": 2497, + "impls": { + "new": { + "nlc": 50, + "total_s": 0.2545866258442402, + "times_s": [ + 0.2545866258442402 + ], + "ms_per_lc": 5.091732516884804, + "lc_per_s": 196.39680534746836, + "n_injected": 25, + "n_recovered": 25, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.74571155601114, + "median_sde_noise": 5.684664549869927, + "per_lc": [ + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005485764238983393, + "SDE": 14.639897802515064, + "chi2_min": 19986.645856211093 + }, + { + "injected": false, + "period": 13.100994110107422, + "T0": 5.437705039673006, + "duration": 0.10437987744808197, + "depth": 0.00097375811310485, + "SDE": 6.510298948327327, + "chi2_min": 19991.359227174664 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005453883670270443, + "SDE": 14.019519939898716, + "chi2_min": 20026.577512524516 + }, + { + "injected": false, + "period": 0.727395236492157, + "T0": 0.3019376498355886, + "duration": 0.0418415404856205, + "depth": 0.0003676938358694315, + "SDE": 5.684664549869927, + "chi2_min": 19321.845612071113 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.00540515873581171, + "SDE": 14.726376734717029, + "chi2_min": 19669.763819709846 + }, + { + "injected": false, + "period": 2.640021324157715, + "T0": 0.4917686880570642, + "duration": 0.07459784299135208, + "depth": 0.0004884963855147362, + "SDE": 6.6571320754623295, + "chi2_min": 19593.49303085074 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005405776668339968, + "SDE": 14.77705988995394, + "chi2_min": 19828.85640417305 + }, + { + "injected": false, + "period": 9.231582641601562, + "T0": 1.668764258751935, + "duration": 0.07619598507881165, + "depth": 0.0008226633653976023, + "SDE": 4.722179100207669, + "chi2_min": 20048.86317008199 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005362111143767834, + "SDE": 14.354143855240103, + "chi2_min": 19451.406444908673 + }, + { + "injected": false, + "period": 1.5595471858978271, + "T0": 0.281584903400649, + "duration": 0.06259265542030334, + "depth": 0.00037873227847740054, + "SDE": 5.943673920026695, + "chi2_min": 19451.819498490713 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005432446021586657, + "SDE": 14.968046725580562, + "chi2_min": 19835.65647686846 + }, + { + "injected": false, + "period": 3.7597527503967285, + "T0": 3.551468894538374, + "duration": 0.09266479313373566, + "depth": 0.0005465572467073798, + "SDE": 4.939380341066058, + "chi2_min": 19562.21720545303 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005425633862614632, + "SDE": 14.533890983898827, + "chi2_min": 19661.441555852696 + }, + { + "injected": false, + "period": 5.938205242156982, + "T0": 1.8585079530804478, + "duration": 0.0977407768368721, + "depth": 0.0006803313735872507, + "SDE": 5.2725448233277605, + "chi2_min": 19645.717433759728 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005327630788087845, + "SDE": 14.84010647678329, + "chi2_min": 19854.839841139597 + }, + { + "injected": false, + "period": 0.6239511370658875, + "T0": 0.1721244509631692, + "duration": 0.03426845371723175, + "depth": 0.0003540570323821157, + "SDE": 6.39481275782302, + "chi2_min": 19814.719961456234 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005372271407395601, + "SDE": 14.723770628688742, + "chi2_min": 19759.874102802845 + }, + { + "injected": false, + "period": 1.7957980632781982, + "T0": 0.0708701585838174, + "duration": 0.048745013773441315, + "depth": 0.00045976031105965376, + "SDE": 6.211765862225475, + "chi2_min": 19886.988311534038 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005604728125035763, + "SDE": 14.90068397890773, + "chi2_min": 19847.307987816148 + }, + { + "injected": false, + "period": 1.7158273458480835, + "T0": 0.7042438654324634, + "duration": 0.04801042377948761, + "depth": 0.0004377198056317866, + "SDE": 4.988946333383417, + "chi2_min": 19686.281949983317 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005634222645312548, + "SDE": 15.213471317734784, + "chi2_min": 20082.62622246992 + }, + { + "injected": false, + "period": 1.944218635559082, + "T0": 1.0748527127935859, + "duration": 0.04533376544713974, + "depth": 0.0005116008687764406, + "SDE": 5.99529671767753, + "chi2_min": 19728.37795666568 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005626666825264692, + "SDE": 14.850588950668095, + "chi2_min": 19887.365185557555 + }, + { + "injected": false, + "period": 5.338284969329834, + "T0": 1.2329951883274148, + "duration": 0.2083013355731964, + "depth": 0.0004553081525955349, + "SDE": 5.298519016483409, + "chi2_min": 19457.346986131895 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005390736740082502, + "SDE": 14.700393260006301, + "chi2_min": 19622.466311638673 + }, + { + "injected": false, + "period": 1.9001942873001099, + "T0": 1.6714522132299692, + "duration": 0.16299022734165192, + "depth": 0.0003048948128707707, + "SDE": 6.3310102071026275, + "chi2_min": 19683.71679549537 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0052563706412911415, + "SDE": 14.640912928082045, + "chi2_min": 19651.33208119841 + }, + { + "injected": false, + "period": 2.132042646408081, + "T0": 1.8807319745508266, + "duration": 0.051615022122859955, + "depth": 0.0005292857531458139, + "SDE": 5.194727590653593, + "chi2_min": 19577.79985606737 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005402364302426577, + "SDE": 14.456168742904701, + "chi2_min": 19436.729586657333 + }, + { + "injected": false, + "period": 2.430079221725464, + "T0": 2.2736688394607825, + "duration": 0.11330521106719971, + "depth": 0.0004198209207970649, + "SDE": 6.671596344814872, + "chi2_min": 19901.711850304608 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005152017343789339, + "SDE": 14.038241987954455, + "chi2_min": 20221.619944051825 + }, + { + "injected": false, + "period": 9.231582641601562, + "T0": 3.019791075150806, + "duration": 0.07619598507881165, + "depth": 0.0008931891061365604, + "SDE": 5.57414069454813, + "chi2_min": 19451.45299624408 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005317769479006529, + "SDE": 15.080195122904549, + "chi2_min": 19643.599153703726 + }, + { + "injected": false, + "period": 8.733040809631348, + "T0": 1.2241375973440398, + "duration": 0.07479896396398544, + "depth": 0.0009044561302289367, + "SDE": 5.237870576812923, + "chi2_min": 19883.518882539494 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005483759101480246, + "SDE": 14.865137839560045, + "chi2_min": 19639.472178093947 + }, + { + "injected": false, + "period": 1.0538432598114014, + "T0": 0.844823486495514, + "duration": 0.05492657795548439, + "depth": 0.0003412514925003052, + "SDE": 7.41383958895593, + "chi2_min": 19181.17701679314 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005476575344800949, + "SDE": 14.959633809165028, + "chi2_min": 19795.391763729953 + }, + { + "injected": false, + "period": 1.7158273458480835, + "T0": 1.437746418930118, + "duration": 0.07496435195207596, + "depth": 0.00039721315260976553, + "SDE": 7.340804439157507, + "chi2_min": 19453.765267702773 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0053500221110880375, + "SDE": 14.900270670406965, + "chi2_min": 20215.64466906669 + }, + { + "injected": false, + "period": 9.213768005371094, + "T0": 3.8128516220795063, + "duration": 0.07614698261022568, + "depth": 0.0008834492764435709, + "SDE": 5.369271475741715, + "chi2_min": 19582.097059867356 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005436438601464033, + "SDE": 15.008994918326797, + "chi2_min": 19810.99344150698 + }, + { + "injected": false, + "period": 1.186469316482544, + "T0": 0.4394331011325221, + "duration": 0.06308804452419281, + "depth": 0.0003383326402399689, + "SDE": 4.907890099401215, + "chi2_min": 19782.61215164576 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005494052078574896, + "SDE": 14.948855768455966, + "chi2_min": 19692.064174238843 + }, + { + "injected": false, + "period": 1.7699131965637207, + "T0": 1.468044076797554, + "duration": 0.04850965365767479, + "depth": 0.0005157210398465395, + "SDE": 6.3993927850147, + "chi2_min": 19890.123616665805 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005343742202967405, + "SDE": 14.74571155601114, + "chi2_min": 19796.72417997518 + }, + { + "injected": false, + "period": 1.6712085008621216, + "T0": 0.23874408222442334, + "duration": 0.05521129071712494, + "depth": 0.00045216272701509297, + "SDE": 6.5008015934644146, + "chi2_min": 19370.162059362396 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005551040638238192, + "SDE": 14.713967185414138, + "chi2_min": 19685.802620606155 + }, + { + "injected": false, + "period": 0.9706023335456848, + "T0": 0.9548758508475785, + "duration": 0.07941237837076187, + "depth": 0.000291008735075593, + "SDE": 5.375330550042362, + "chi2_min": 20024.64889769606 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005364943295717239, + "SDE": 14.32465841986806, + "chi2_min": 19449.195780767288 + }, + { + "injected": false, + "period": 3.3878562450408936, + "T0": 2.2401032092012088, + "duration": 0.06023088097572327, + "depth": 0.0006338467355817556, + "SDE": 5.240739427079039, + "chi2_min": 19773.893695076826 + } + ] + } + } + }, + "tess-yr": { + "config": { + "ndata": 16850, + "baseline": 351.0, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 21.7, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 175.0, + "nlc": 20 + }, + "nlc": 20, + "nperiods": 42001, + "impls": { + "new": { + "nlc": 20, + "total_s": 0.5467865355312824, + "times_s": [ + 0.5467865355312824 + ], + "ms_per_lc": 27.33932677656412, + "lc_per_s": 36.57734545450557, + "n_injected": 10, + "n_recovered": 10, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 52.45753681285535, + "median_sde_noise": 8.462351870001159, + "per_lc": [ + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.00428521353751421, + "SDE": 51.74706353724402, + "chi2_min": 17045.304161600427 + }, + { + "injected": false, + "period": 71.1637191772461, + "T0": 34.1104773348261, + "duration": 0.19279845058918, + "depth": 0.0008943733409978449, + "SDE": 8.028486663164024, + "chi2_min": 16855.451608264993 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004315289203077555, + "SDE": 53.579226489536495, + "chi2_min": 17079.369669986347 + }, + { + "injected": false, + "period": 3.215691566467285, + "T0": 2.7022411507869606, + "duration": 0.05919283628463745, + "depth": 0.00034801653237082064, + "SDE": 6.9967664551079904, + "chi2_min": 16563.562434798696 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004378140438348055, + "SDE": 51.417002515500876, + "chi2_min": 16690.807726532905 + }, + { + "injected": false, + "period": 1.5765894651412964, + "T0": 1.1244638781501877, + "duration": 0.046674944460392, + "depth": 0.00028764992021024227, + "SDE": 9.104482343494766, + "chi2_min": 16943.34078928957 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004271374084055424, + "SDE": 53.34992635726429, + "chi2_min": 16960.625747997896 + }, + { + "injected": false, + "period": 13.20435905456543, + "T0": 1.339143794434733, + "duration": 0.2093072384595871, + "depth": 0.00039136491250246763, + "SDE": 8.470054973388613, + "chi2_min": 16618.206479002816 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004417836666107178, + "SDE": 52.79030615750608, + "chi2_min": 17073.47447652764 + }, + { + "injected": false, + "period": 1.0810301303863525, + "T0": 0.8323784887314218, + "duration": 0.03727799281477928, + "depth": 0.00030446742312051356, + "SDE": 12.367127339046329, + "chi2_min": 16803.589990291133 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.0041633895598351955, + "SDE": 51.3055595838171, + "chi2_min": 17136.81803806736 + }, + { + "injected": false, + "period": 35.858131408691406, + "T0": 3.57559711400188, + "duration": 0.30683863162994385, + "depth": 0.0005235545104369521, + "SDE": 7.264360780878907, + "chi2_min": 16644.461869314277 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.0043487101793289185, + "SDE": 53.18143485280267, + "chi2_min": 17383.538593224726 + }, + { + "injected": false, + "period": 1.4476821422576904, + "T0": 1.3089501248304032, + "duration": 0.04536651819944382, + "depth": 0.00027384364511817694, + "SDE": 8.454648766613705, + "chi2_min": 17168.875156750462 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.0043377201072871685, + "SDE": 52.124767468204624, + "chi2_min": 17070.551816905958 + }, + { + "injected": false, + "period": 158.73745727539062, + "T0": 94.37186024718721, + "duration": 0.3933356702327728, + "depth": 0.0010018610628321767, + "SDE": 7.243525185957916, + "chi2_min": 16733.71459318848 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004398010671138763, + "SDE": 52.852382712238594, + "chi2_min": 17030.781448475514 + }, + { + "injected": false, + "period": 143.65647888183594, + "T0": 105.68818444369845, + "duration": 0.23189450800418854, + "depth": 0.0014297961024567485, + "SDE": 9.032557748466932, + "chi2_min": 16928.81373207052 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.2470066249370575, + "depth": 0.004301433917135, + "SDE": 50.82005769699972, + "chi2_min": 16781.757778621162 + }, + { + "injected": false, + "period": 1.0684576034545898, + "T0": 0.9389372063940868, + "duration": 0.04099807143211365, + "depth": 0.000271445867838338, + "SDE": 9.543209397347338, + "chi2_min": 16826.68702423067 + } + ] + } + } + }, + "kepler-4yr": { + "config": { + "ndata": 65440, + "baseline": 1363.0, + "cadence": 0.020833333333333332, + "noise": 0.0006, + "inject_period": 41.3, + "inject_depth": 0.003, + "period_min": 0.6, + "period_max": 500.0, + "nlc": 10 + }, + "nlc": 10, + "nperiods": 171688, + "impls": { + "new": { + "nlc": 10, + "total_s": 1.9777560979127884, + "times_s": [ + 1.9777560979127884 + ], + "ms_per_lc": 197.77560979127884, + "lc_per_s": 5.056235200363398, + "n_injected": 5, + "n_recovered": 5, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 98.29821322567172, + "median_sde_noise": 8.72215844392861, + "per_lc": [ + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003353167325258255, + "SDE": 98.45695607941019, + "chi2_min": 65888.8686123984 + }, + { + "injected": false, + "period": 55.92778396606445, + "T0": 50.19175134709553, + "duration": 0.16932636499404907, + "depth": 0.0003138199681416154, + "SDE": 8.72215844392861, + "chi2_min": 65560.97205817862 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003339726710692048, + "SDE": 100.12524747056952, + "chi2_min": 66294.66735087954 + }, + { + "injected": false, + "period": 131.69247436523438, + "T0": 60.8605908603713, + "duration": 0.20403198897838593, + "depth": 0.0004167061997577548, + "SDE": 8.661975668401452, + "chi2_min": 65907.71342974457 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0033489372581243515, + "SDE": 97.03154083286489, + "chi2_min": 66182.91527186599 + }, + { + "injected": false, + "period": 96.05792236328125, + "T0": 50.60741073171448, + "duration": 0.2130729854106903, + "depth": 0.00037875358248129487, + "SDE": 11.123223521227903, + "chi2_min": 65325.414736351566 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003390850266441703, + "SDE": 98.01942805850948, + "chi2_min": 66280.838278687 + }, + { + "injected": false, + "period": 164.4737091064453, + "T0": 46.597844866974356, + "duration": 0.23087593913078308, + "depth": 0.0004218894464429468, + "SDE": 7.961574427646926, + "chi2_min": 65834.8010161592 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0033445751760154963, + "SDE": 98.29821322567172, + "chi2_min": 66655.12926137832 + }, + { + "injected": false, + "period": 2.184530735015869, + "T0": 1.3664060570654044, + "duration": 0.10407035797834396, + "depth": 7.64523065299727e-05, + "SDE": 9.621357122108616, + "chi2_min": 65125.09877587645 + } + ] + } + } + } + }, + "env": { + "python": "3.11.10", + "numpy": "2.4.6", + "hostname": "299dee83312d", + "cpu_count": 40, + "cuvarbase": "1.0.0", + "pycuda": "2026.1", + "cuda_driver_version": 12060, + "gpu": "NVIDIA RTX 4000 Ada Generation", + "compute_capability": "8.9", + "nvcc": "Cuda compilation tools, release 12.4, V12.4.131" + } +} \ No newline at end of file diff --git a/benchmarks/results/tls_survey_jul2026/tls_survey_v100.json b/benchmarks/results/tls_survey_jul2026/tls_survey_v100.json new file mode 100644 index 0000000..f6b70d2 --- /dev/null +++ b/benchmarks/results/tls_survey_jul2026/tls_survey_v100.json @@ -0,0 +1,2269 @@ +{ + "script": "benchmark_tls_survey.py", + "timestamp": "2026-07-06T18:19:15", + "args": { + "regimes": "tess-ffi,k2,tess-2min,tess-yr,kepler-4yr", + "nlc": null, + "impls": "new", + "ref_nlc": 1, + "old_nlc": 5, + "n_iter": 1, + "output": "tls_survey_v100.json", + "quick": false, + "ref_all": false + }, + "regimes": { + "tess-ffi": { + "config": { + "ndata": 1310, + "baseline": 27.4, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 7.7, + "inject_depth": 0.005, + "period_min": 0.6, + "period_max": 13.7, + "nlc": 100 + }, + "nlc": 100, + "nperiods": 2486, + "impls": { + "new": { + "nlc": 100, + "total_s": 0.14208540692925453, + "times_s": [ + 0.14208540692925453 + ], + "ms_per_lc": 1.4208540692925453, + "lc_per_s": 703.8020452711995, + "n_injected": 50, + "n_recovered": 50, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.057206183863471, + "median_sde_noise": 5.4799220937731, + "per_lc": [ + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004994536284357309, + "SDE": 13.824748211231611, + "chi2_min": 1343.3166566172576 + }, + { + "injected": false, + "period": 0.6225233674049377, + "T0": 0.542300333010111, + "duration": 0.037806544452905655, + "depth": 0.0005099073168821633, + "SDE": 4.320592343053708, + "chi2_min": 1315.8272696594818 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004595326259732246, + "SDE": 14.151275870863943, + "chi2_min": 1388.0540178442573 + }, + { + "injected": false, + "period": 2.0671958923339844, + "T0": 1.240600977982922, + "duration": 0.04627010226249695, + "depth": 0.0010054809972643852, + "SDE": 5.439224604982493, + "chi2_min": 1312.4691889973124 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.0052549876272678375, + "SDE": 13.546964383908636, + "chi2_min": 1225.6534163995327 + }, + { + "injected": false, + "period": 6.83004903793335, + "T0": 3.3232153407358425, + "duration": 0.14482606947422028, + "depth": 0.0009646486141718924, + "SDE": 5.193850131189129, + "chi2_min": 1239.76099682099 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3137119733402045, + "duration": 0.15838181972503662, + "depth": 0.005142259411513805, + "SDE": 14.291874487780534, + "chi2_min": 1270.7130377876167 + }, + { + "injected": false, + "period": 1.3832758665084839, + "T0": 1.2075118932858473, + "duration": 0.0404709056019783, + "depth": 0.0009033045498654246, + "SDE": 6.169803249922114, + "chi2_min": 1265.5680106485863 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0049972208216786385, + "SDE": 14.095804734228182, + "chi2_min": 1245.5418060909765 + }, + { + "injected": false, + "period": 9.259944915771484, + "T0": 5.364545925151106, + "duration": 0.12514053285121918, + "depth": 0.001239022589288652, + "SDE": 4.375034616567076, + "chi2_min": 1306.7850229998053 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.316541905906817, + "duration": 0.15838171541690826, + "depth": 0.00510247191414237, + "SDE": 12.857307581446387, + "chi2_min": 1379.8338405984605 + }, + { + "injected": false, + "period": 4.670420169830322, + "T0": 1.2254929261115564, + "duration": 0.06071445345878601, + "depth": 0.0012486246414482594, + "SDE": 5.22776518169518, + "chi2_min": 1277.774256301244 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.005526317749172449, + "SDE": 14.447433380924723, + "chi2_min": 1311.2708009539028 + }, + { + "injected": false, + "period": 0.694443941116333, + "T0": 0.5399806443484323, + "duration": 0.039209768176078796, + "depth": 0.000674063281621784, + "SDE": 5.792146913416813, + "chi2_min": 1375.2101674319447 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0049413591623306274, + "SDE": 14.09302631161843, + "chi2_min": 1403.870365483287 + }, + { + "injected": false, + "period": 0.9697667956352234, + "T0": 0.6234215032222714, + "duration": 0.04170956835150719, + "depth": 0.0007125452975742519, + "SDE": 6.053405113355577, + "chi2_min": 1344.0566340195523 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3137119733402045, + "duration": 0.15838181972503662, + "depth": 0.004847251810133457, + "SDE": 14.767257239752563, + "chi2_min": 1377.8351044304827 + }, + { + "injected": false, + "period": 7.037842750549316, + "T0": 1.9062626516681007, + "duration": 0.10343571752309799, + "depth": 0.001075836131349206, + "SDE": 5.550556064393794, + "chi2_min": 1407.0896937434245 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005022849887609482, + "SDE": 13.957691254586013, + "chi2_min": 1322.2117583682011 + }, + { + "injected": false, + "period": 6.641885280609131, + "T0": 1.800826401364219, + "duration": 0.08745435625314713, + "depth": 0.0012787478044629097, + "SDE": 6.51261874832097, + "chi2_min": 1293.3742648347863 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005061832722276449, + "SDE": 14.154451528325065, + "chi2_min": 1238.058633257935 + }, + { + "injected": false, + "period": 3.6306135654449463, + "T0": 1.9492430389519342, + "duration": 0.07513566315174103, + "depth": 0.0009633752051740885, + "SDE": 4.791418499333642, + "chi2_min": 1307.175808758614 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004871276672929525, + "SDE": 13.861185994893118, + "chi2_min": 1375.5374651029479 + }, + { + "injected": false, + "period": 1.812753677368164, + "T0": 1.3972279533641085, + "duration": 0.044288016855716705, + "depth": 0.0008740366320125759, + "SDE": 7.094830302098393, + "chi2_min": 1327.0709532199096 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004978665150702, + "SDE": 14.008937983018118, + "chi2_min": 1321.4317776885973 + }, + { + "injected": false, + "period": 13.635416984558105, + "T0": 0.11372829471468915, + "duration": 0.23358194530010223, + "depth": 0.0010562270181253552, + "SDE": 4.921974250260108, + "chi2_min": 1330.9486482442412 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004547102842479944, + "SDE": 14.403645846421027, + "chi2_min": 1272.013336329653 + }, + { + "injected": false, + "period": 5.856029033660889, + "T0": 3.841079401770827, + "duration": 0.09728776663541794, + "depth": 0.0009948982624337077, + "SDE": 6.013786949469513, + "chi2_min": 1271.3009490778647 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005151343997567892, + "SDE": 15.248616738183886, + "chi2_min": 1373.4479058239203 + }, + { + "injected": false, + "period": 9.743551254272461, + "T0": 5.753852141378843, + "duration": 0.08565451949834824, + "depth": 0.0014769668923690915, + "SDE": 5.346068202165282, + "chi2_min": 1212.8167884247855 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0048437039367854595, + "SDE": 14.55587314234365, + "chi2_min": 1276.2413443851192 + }, + { + "injected": false, + "period": 2.9746532440185547, + "T0": 1.2400459967608413, + "duration": 0.20895150303840637, + "depth": 0.0005317212198860943, + "SDE": 4.615297616613198, + "chi2_min": 1313.5703095084912 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004542770329862833, + "SDE": 14.504544196348368, + "chi2_min": 1375.4844324690948 + }, + { + "injected": false, + "period": 12.579136848449707, + "T0": 4.226824228778526, + "duration": 0.1194644570350647, + "depth": 0.001611640676856041, + "SDE": 5.3635396403655635, + "chi2_min": 1262.274012928982 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.302647882457407, + "duration": 0.19306959211826324, + "depth": 0.004228070843964815, + "SDE": 13.759452625846706, + "chi2_min": 1377.3826188324651 + }, + { + "injected": false, + "period": 2.6725428104400635, + "T0": 0.14387011199786048, + "duration": 0.05565265938639641, + "depth": 0.0009991604601964355, + "SDE": 6.7267399117552555, + "chi2_min": 1288.3582232156282 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00502576120197773, + "SDE": 14.021386056108513, + "chi2_min": 1430.8644369249123 + }, + { + "injected": false, + "period": 0.6743714809417725, + "T0": 0.46929139088928196, + "duration": 0.03346893936395645, + "depth": 0.0006973492563702166, + "SDE": 6.370018960348677, + "chi2_min": 1295.8512727122784 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.00511719798669219, + "SDE": 14.77100328882694, + "chi2_min": 1337.5560828564667 + }, + { + "injected": false, + "period": 12.07891845703125, + "T0": 3.4772668477962725, + "duration": 0.08333925157785416, + "depth": 0.001632323837839067, + "SDE": 5.126722349181245, + "chi2_min": 1315.9131548805497 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0051468717865645885, + "SDE": 13.857145590801544, + "chi2_min": 1246.5068408102534 + }, + { + "injected": false, + "period": 10.641645431518555, + "T0": 0.5814596127869152, + "duration": 0.07989320904016495, + "depth": 0.0015373544301837683, + "SDE": 4.655717986306318, + "chi2_min": 1302.4757446433 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004942566622048616, + "SDE": 14.40184200098637, + "chi2_min": 1306.720259772929 + }, + { + "injected": false, + "period": 1.0845619440078735, + "T0": 0.4145796007128588, + "duration": 0.039212726056575775, + "depth": 0.000743131386116147, + "SDE": 6.100442711846552, + "chi2_min": 1303.0670491921926 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004929995629936457, + "SDE": 13.311797451577288, + "chi2_min": 1336.85502704256 + }, + { + "injected": false, + "period": 3.751904010772705, + "T0": 1.6228371537112594, + "duration": 0.05644047260284424, + "depth": 0.0011902560945600271, + "SDE": 5.192978874403368, + "chi2_min": 1326.865363732231 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004629185423254967, + "SDE": 13.060570324782994, + "chi2_min": 1239.7685167948307 + }, + { + "injected": false, + "period": 5.536378383636475, + "T0": 2.694534725723358, + "duration": 0.06751765310764313, + "depth": 0.0012676733313128352, + "SDE": 4.190803883585782, + "chi2_min": 1266.8976156958374 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3137119733402045, + "duration": 0.15838181972503662, + "depth": 0.004855481907725334, + "SDE": 14.221075719241638, + "chi2_min": 1315.0935318110098 + }, + { + "injected": false, + "period": 9.36865520477295, + "T0": 9.22744536080586, + "duration": 0.1387048214673996, + "depth": 0.0015655959723517299, + "SDE": 6.573981845759308, + "chi2_min": 1252.7033290656664 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005103591829538345, + "SDE": 13.910988186928549, + "chi2_min": 1324.800854724087 + }, + { + "injected": false, + "period": 0.8091202974319458, + "T0": 0.4505333795458242, + "duration": 0.04125908017158508, + "depth": 0.0006217345944605768, + "SDE": 5.649665856513129, + "chi2_min": 1371.453913303614 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004763154312968254, + "SDE": 13.796502676638335, + "chi2_min": 1279.762928250731 + }, + { + "injected": false, + "period": 0.8660217523574829, + "T0": 0.2381559870601997, + "duration": 0.06924363225698471, + "depth": 0.0005305147496983409, + "SDE": 7.01535326577632, + "chi2_min": 1301.5783518420176 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004730703309178352, + "SDE": 14.60839151498775, + "chi2_min": 1307.0834198059863 + }, + { + "injected": false, + "period": 1.0024302005767822, + "T0": 0.27075475157906936, + "duration": 0.11352045834064484, + "depth": 0.0003724353446159512, + "SDE": 5.520619582563706, + "chi2_min": 1208.8534825681932 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004943359177559614, + "SDE": 13.40104079345133, + "chi2_min": 1389.8745100263664 + }, + { + "injected": false, + "period": 0.620072603225708, + "T0": 0.2626584416756259, + "duration": 0.041687000542879105, + "depth": 0.0005490335170179605, + "SDE": 5.357486698310393, + "chi2_min": 1290.547582586565 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.004910163581371307, + "SDE": 14.315323817402604, + "chi2_min": 1313.1217309836666 + }, + { + "injected": false, + "period": 1.4328784942626953, + "T0": 1.2479081935049408, + "duration": 0.04094899445772171, + "depth": 0.0008829569560475647, + "SDE": 5.731119660990421, + "chi2_min": 1376.3152012276637 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004564641043543816, + "SDE": 13.656022960128118, + "chi2_min": 1420.0044340134655 + }, + { + "injected": false, + "period": 2.585336923599243, + "T0": 0.923334637585171, + "duration": 0.13419054448604584, + "depth": 0.000590515963267535, + "SDE": 5.171262197650821, + "chi2_min": 1296.9976288289213 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004706313833594322, + "SDE": 14.58284643855217, + "chi2_min": 1330.1767404106772 + }, + { + "injected": false, + "period": 5.164575099945068, + "T0": 0.5105161548749209, + "duration": 0.19606541097164154, + "depth": 0.0006265363190323114, + "SDE": 5.017631694776126, + "chi2_min": 1278.853556208874 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004956825636327267, + "SDE": 13.465916954927257, + "chi2_min": 1308.3404156230947 + }, + { + "injected": false, + "period": 2.7281653881073, + "T0": 1.4655267958866602, + "duration": 0.05603610351681709, + "depth": 0.0008929938194341958, + "SDE": 5.563565738371344, + "chi2_min": 1255.0453176588635 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.005156008061021566, + "SDE": 13.469434386162332, + "chi2_min": 1283.244246956347 + }, + { + "injected": false, + "period": 4.76552152633667, + "T0": 1.076287644484374, + "duration": 0.06422623991966248, + "depth": 0.0012868511257693172, + "SDE": 5.748693712562537, + "chi2_min": 1269.2160331464397 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004850361030548811, + "SDE": 13.615283922648205, + "chi2_min": 1458.0778547256632 + }, + { + "injected": false, + "period": 5.954711437225342, + "T0": 4.000462559284301, + "duration": 0.06583552062511444, + "depth": 0.001470325980335474, + "SDE": 4.281483931070663, + "chi2_min": 1338.0946768454855 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3166635296710325, + "duration": 0.17486760020256042, + "depth": 0.004960371181368828, + "SDE": 13.76555275711953, + "chi2_min": 1231.1977440257347 + }, + { + "injected": false, + "period": 2.147103786468506, + "T0": 1.9348414355212356, + "duration": 0.0768798366189003, + "depth": 0.0006785376463085413, + "SDE": 5.68102410812672, + "chi2_min": 1183.5185653415458 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.004848890006542206, + "SDE": 13.769896752821715, + "chi2_min": 1365.883146663318 + }, + { + "injected": false, + "period": 2.8218910694122314, + "T0": 0.3113438265453894, + "duration": 0.06908220052719116, + "depth": 0.0010092707816511393, + "SDE": 6.640720602015786, + "chi2_min": 1299.333389310017 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004796753637492657, + "SDE": 14.298441701791154, + "chi2_min": 1280.7008868362532 + }, + { + "injected": false, + "period": 7.533771991729736, + "T0": 2.411801624352279, + "duration": 0.07481919229030609, + "depth": 0.0013799527660012245, + "SDE": 5.8061339876057625, + "chi2_min": 1291.9232631751825 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004743710160255432, + "SDE": 13.22648309749417, + "chi2_min": 1329.3352469008983 + }, + { + "injected": false, + "period": 2.043039560317993, + "T0": 0.20179237219836565, + "duration": 0.046089161187410355, + "depth": 0.0008912621415220201, + "SDE": 5.4377927880629615, + "chi2_min": 1391.1062161528182 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.302647882457407, + "duration": 0.19306959211826324, + "depth": 0.004489851649850607, + "SDE": 13.125461259691887, + "chi2_min": 1341.6502881792726 + }, + { + "injected": false, + "period": 3.65653133392334, + "T0": 0.8910219764560026, + "duration": 0.06178278848528862, + "depth": 0.0010194219648838043, + "SDE": 5.065225246362491, + "chi2_min": 1227.876746646248 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3137119733402045, + "duration": 0.15838181972503662, + "depth": 0.00521567277610302, + "SDE": 15.189097276543496, + "chi2_min": 1232.31205538533 + }, + { + "injected": false, + "period": 4.433368682861328, + "T0": 3.8581784102236725, + "duration": 0.059669382870197296, + "depth": 0.0012552980333566666, + "SDE": 5.399391539559226, + "chi2_min": 1283.402894008224 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005188316572457552, + "SDE": 13.25389997547865, + "chi2_min": 1389.190251579791 + }, + { + "injected": false, + "period": 10.13871955871582, + "T0": 1.3899856289888248, + "duration": 0.2579602003097534, + "depth": 0.0008953508804552257, + "SDE": 5.796619746385799, + "chi2_min": 1317.9714885779986 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.005047174636274576, + "SDE": 14.183686802971941, + "chi2_min": 1302.187000072226 + }, + { + "injected": false, + "period": 13.635416984558105, + "T0": 4.660816806064474, + "duration": 0.1823594868183136, + "depth": 0.0012732133036479354, + "SDE": 5.8839950242694625, + "chi2_min": 1202.6427141749414 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004888550844043493, + "SDE": 13.425439410650005, + "chi2_min": 1331.2404926821323 + }, + { + "injected": false, + "period": 12.15611457824707, + "T0": 4.850591000732152, + "duration": 0.13702285289764404, + "depth": 0.0013082606019452214, + "SDE": 4.783097993755491, + "chi2_min": 1277.6464594489116 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.0047805835492908955, + "SDE": 14.1119977020878, + "chi2_min": 1400.117006611571 + }, + { + "injected": false, + "period": 9.978133201599121, + "T0": 3.989828930425375, + "duration": 0.23240043222904205, + "depth": 0.0010685203596949577, + "SDE": 7.026146879570354, + "chi2_min": 1309.7399345544522 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004954393021762371, + "SDE": 13.472370335921822, + "chi2_min": 1305.724756346867 + }, + { + "injected": false, + "period": 1.227888584136963, + "T0": 0.23685326980719879, + "duration": 0.047413453459739685, + "depth": 0.0007900178316049278, + "SDE": 6.718391751540111, + "chi2_min": 1253.6789144942313 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3166635296710325, + "duration": 0.17486760020256042, + "depth": 0.0045309956185519695, + "SDE": 14.40717291491021, + "chi2_min": 1352.9125401937622 + }, + { + "injected": false, + "period": 2.2177605628967285, + "T0": 1.0043958503840145, + "duration": 0.06375162303447723, + "depth": 0.0008319917833432555, + "SDE": 5.2101067543342205, + "chi2_min": 1338.2337130712012 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.309144427296914, + "duration": 0.15838181972503662, + "depth": 0.005017078015953302, + "SDE": 14.55090687210087, + "chi2_min": 1368.1301150405575 + }, + { + "injected": false, + "period": 3.958618640899658, + "T0": 1.5509364717303242, + "duration": 0.0574585385620594, + "depth": 0.001214984804391861, + "SDE": 4.823721460791652, + "chi2_min": 1282.229853361992 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004880807362496853, + "SDE": 15.11338851387768, + "chi2_min": 1347.1430297698878 + }, + { + "injected": false, + "period": 12.312492370605469, + "T0": 0.625243753194809, + "duration": 0.15193158388137817, + "depth": 0.0011966126039624214, + "SDE": 6.127166003183497, + "chi2_min": 1332.4424726820241 + }, + { + "injected": true, + "period": 7.70003080368042, + "T0": 2.3110956855367704, + "duration": 0.17486760020256042, + "depth": 0.004942622501403093, + "SDE": 14.79142907107735, + "chi2_min": 1355.3571954551194 + }, + { + "injected": false, + "period": 6.318080902099609, + "T0": 0.02583512814802269, + "duration": 0.09978199750185013, + "depth": 0.0009755137725733221, + "SDE": 4.651989778407932, + "chi2_min": 1247.792465656339 + } + ] + } + } + }, + "k2": { + "config": { + "ndata": 4320, + "baseline": 90.0, + "cadence": 0.020833333333333332, + "noise": 0.0008, + "inject_period": 12.4, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 45.0, + "nlc": 50 + }, + "nlc": 50, + "nperiods": 9672, + "impls": { + "new": { + "nlc": 50, + "total_s": 0.19335215166211128, + "times_s": [ + 0.19335215166211128 + ], + "ms_per_lc": 3.8670430332422256, + "lc_per_s": 258.5955189543301, + "n_injected": 25, + "n_recovered": 25, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 25.201212996804028, + "median_sde_noise": 6.574796123467906, + "per_lc": [ + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.18565721809864044, + "depth": 0.004096044693142176, + "SDE": 25.886694644591515, + "chi2_min": 4383.846413776024 + }, + { + "injected": false, + "period": 1.3685027360916138, + "T0": 0.9995278422767413, + "duration": 0.044523872435092926, + "depth": 0.0003543264465406537, + "SDE": 6.372890809448275, + "chi2_min": 4326.31600577895 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.00405429070815444, + "SDE": 25.35949977734318, + "chi2_min": 4391.303049965471 + }, + { + "injected": false, + "period": 1.567154884338379, + "T0": 0.6710433548500703, + "duration": 0.04433155059814453, + "depth": 0.0004464688536245376, + "SDE": 10.254838885848923, + "chi2_min": 4247.198331220121 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004084067884832621, + "SDE": 24.924516382187875, + "chi2_min": 4380.199625335411 + }, + { + "injected": false, + "period": 17.946809768676758, + "T0": 11.771186328499653, + "duration": 0.19019503891468048, + "depth": 0.0006513726548291743, + "SDE": 6.598806967575485, + "chi2_min": 4313.265534728922 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.18565721809864044, + "depth": 0.004031355958431959, + "SDE": 25.96822627870716, + "chi2_min": 4326.187839532829 + }, + { + "injected": false, + "period": 7.355057716369629, + "T0": 1.9938212273293345, + "duration": 0.09989657998085022, + "depth": 0.0005613853572867811, + "SDE": 6.574796123467906, + "chi2_min": 4085.3548769271165 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.0040359050035476685, + "SDE": 26.060700847892555, + "chi2_min": 4419.476137500889 + }, + { + "injected": false, + "period": 1.7254761457443237, + "T0": 0.08025470415425229, + "duration": 0.11726968735456467, + "depth": 0.0002659271704033017, + "SDE": 8.915781523713441, + "chi2_min": 4256.026837373626 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.0040281713008880615, + "SDE": 24.336495976466068, + "chi2_min": 4453.034095279101 + }, + { + "injected": false, + "period": 44.27975845336914, + "T0": 8.941723780283041, + "duration": 0.3819054961204529, + "depth": 0.0006938476581126451, + "SDE": 5.626467295929954, + "chi2_min": 4325.792513737073 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.18565721809864044, + "depth": 0.003936475608497858, + "SDE": 24.49283173357621, + "chi2_min": 4373.98567632751 + }, + { + "injected": false, + "period": 13.618805885314941, + "T0": 12.356419633092571, + "duration": 0.10573731362819672, + "depth": 0.0008530879858881235, + "SDE": 6.705846573149672, + "chi2_min": 4296.93668910697 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.003946550656110048, + "SDE": 24.398364317727268, + "chi2_min": 4258.882833025552 + }, + { + "injected": false, + "period": 8.089868545532227, + "T0": 4.885035835718213, + "duration": 0.0888851210474968, + "depth": 0.0007029274711385369, + "SDE": 6.53334233889305, + "chi2_min": 4083.083096396621 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.003970298916101456, + "SDE": 23.86850258430663, + "chi2_min": 4308.172160564909 + }, + { + "injected": false, + "period": 11.277223587036133, + "T0": 2.307841625154026, + "duration": 0.15503697097301483, + "depth": 0.0005774652818217874, + "SDE": 5.756786244378622, + "chi2_min": 4249.9400512796165 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004039672203361988, + "SDE": 25.41096291795666, + "chi2_min": 4242.778836320764 + }, + { + "injected": false, + "period": 2.755979537963867, + "T0": 2.585970627129086, + "duration": 0.056225892156362534, + "depth": 0.00044577528024092317, + "SDE": 6.9204886710698545, + "chi2_min": 4302.643274483636 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.18565721809864044, + "depth": 0.0038935276679694653, + "SDE": 24.831492887384506, + "chi2_min": 4440.216790777311 + }, + { + "injected": false, + "period": 7.901713848114014, + "T0": 5.555892549455166, + "duration": 0.09737034142017365, + "depth": 0.0006193366716615856, + "SDE": 6.68314073340143, + "chi2_min": 4281.997379277592 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7084950072158165, + "duration": 0.18565721809864044, + "depth": 0.004017242230474949, + "SDE": 25.201212996804028, + "chi2_min": 4254.131613738577 + }, + { + "injected": false, + "period": 2.0137128829956055, + "T0": 1.3468567478449245, + "duration": 0.05064193159341812, + "depth": 0.00047726265620440245, + "SDE": 10.683345388634434, + "chi2_min": 4280.127469283618 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004109283909201622, + "SDE": 25.27781326050563, + "chi2_min": 4399.7225532298435 + }, + { + "injected": false, + "period": 2.7014899253845215, + "T0": 1.6762021150968565, + "duration": 0.07898787409067154, + "depth": 0.0003673879546113312, + "SDE": 5.476729717225788, + "chi2_min": 4098.632586503525 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.0039016627706587315, + "SDE": 26.22208666482348, + "chi2_min": 4505.634883884901 + }, + { + "injected": false, + "period": 10.265218734741211, + "T0": 3.1679013496663515, + "duration": 0.08715666830539703, + "depth": 0.000743471086025238, + "SDE": 8.06459904646771, + "chi2_min": 4252.67821601574 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.18565721809864044, + "depth": 0.004194461274892092, + "SDE": 24.543167263490176, + "chi2_min": 4461.4037472014825 + }, + { + "injected": false, + "period": 30.56487464904785, + "T0": 7.08230056832997, + "duration": 0.12538689374923706, + "depth": 0.0011026031570509076, + "SDE": 6.298550328825552, + "chi2_min": 4207.851691121158 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.0040408591739833355, + "SDE": 25.53118224669925, + "chi2_min": 4363.073542174787 + }, + { + "injected": false, + "period": 36.307926177978516, + "T0": 19.91623931560639, + "duration": 0.29323291778564453, + "depth": 0.0008949660114012659, + "SDE": 6.136413000415641, + "chi2_min": 4425.171017602781 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.0040709576569497585, + "SDE": 25.385079949472022, + "chi2_min": 4399.550720448655 + }, + { + "injected": false, + "period": 3.1908771991729736, + "T0": 0.5407807732185823, + "duration": 0.06849425286054611, + "depth": 0.00045074979425407946, + "SDE": 6.943886854996949, + "chi2_min": 4250.652292281888 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.00394544517621398, + "SDE": 27.331136154734367, + "chi2_min": 4300.823115539585 + }, + { + "injected": false, + "period": 1.1502342224121094, + "T0": 0.197360137900489, + "duration": 0.04639210179448128, + "depth": 0.00033418359817005694, + "SDE": 6.551303311164812, + "chi2_min": 4534.204394161627 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.004040546249598265, + "SDE": 26.440717679789405, + "chi2_min": 4497.820694266335 + }, + { + "injected": false, + "period": 5.21898889541626, + "T0": 1.9571208357810974, + "duration": 0.20673802495002747, + "depth": 0.00033009087201207876, + "SDE": 6.867265125261597, + "chi2_min": 4315.49914623832 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.0041288407519459724, + "SDE": 25.179250185027833, + "chi2_min": 4414.150812193026 + }, + { + "injected": false, + "period": 14.592304229736328, + "T0": 8.439254865465955, + "duration": 0.0932646244764328, + "depth": 0.0008997920085676014, + "SDE": 6.432134855816056, + "chi2_min": 4359.845241377803 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.0038928925059735775, + "SDE": 25.628381969887695, + "chi2_min": 4501.120579865637 + }, + { + "injected": false, + "period": 12.45097541809082, + "T0": 9.853753344433017, + "duration": 0.13812200725078583, + "depth": 0.0007385652279481292, + "SDE": 7.190493045627132, + "chi2_min": 4299.71282535054 + }, + { + "injected": true, + "period": 12.39454174041748, + "T0": 3.7385776951641674, + "duration": 0.20493797957897186, + "depth": 0.0037482825573533773, + "SDE": 24.781014409494773, + "chi2_min": 4330.148849653211 + }, + { + "injected": false, + "period": 6.057334899902344, + "T0": 3.0855804639822964, + "duration": 0.07310348004102707, + "depth": 0.0005771773867309093, + "SDE": 5.39455810967937, + "chi2_min": 4106.679127490111 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.18565721809864044, + "depth": 0.004012775141745806, + "SDE": 24.565142946018387, + "chi2_min": 4548.415883455946 + }, + { + "injected": false, + "period": 1.9488736391067505, + "T0": 1.2610359251262224, + "duration": 0.16437040269374847, + "depth": 0.0002546783653087914, + "SDE": 5.335259812758131, + "chi2_min": 4367.933386772307 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.71311754722862, + "duration": 0.19508059322834015, + "depth": 0.003971559461206198, + "SDE": 24.320701609068305, + "chi2_min": 4388.407499494195 + }, + { + "injected": false, + "period": 20.636655807495117, + "T0": 1.2264171468407028, + "duration": 0.09962917864322662, + "depth": 0.0008535315282642841, + "SDE": 7.449187261085652, + "chi2_min": 4368.517917848931 + }, + { + "injected": true, + "period": 12.402583122253418, + "T0": 3.7072057524929107, + "duration": 0.19508059322834015, + "depth": 0.004027797374874353, + "SDE": 24.936090114669174, + "chi2_min": 4538.718273606291 + }, + { + "injected": false, + "period": 1.4916346073150635, + "T0": 0.13033700851491936, + "duration": 0.04582108184695244, + "depth": 0.00038103508995845914, + "SDE": 6.140997664777387, + "chi2_min": 4323.307037834129 + } + ] + } + } + }, + "tess-2min": { + "config": { + "ndata": 19710, + "baseline": 27.4, + "cadence": 0.001388888888888889, + "noise": 0.002, + "inject_period": 7.7, + "inject_depth": 0.005, + "period_min": 0.6, + "period_max": 13.7, + "nlc": 50 + }, + "nlc": 50, + "nperiods": 2497, + "impls": { + "new": { + "nlc": 50, + "total_s": 0.15442728251218796, + "times_s": [ + 0.15442728251218796 + ], + "ms_per_lc": 3.088545650243759, + "lc_per_s": 323.776985430368, + "n_injected": 25, + "n_recovered": 25, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 14.631184017496109, + "median_sde_noise": 5.8276992197673065, + "per_lc": [ + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0049664671532809734, + "SDE": 14.511805973437204, + "chi2_min": 19987.608990976718 + }, + { + "injected": false, + "period": 13.100994110107422, + "T0": 5.437705039673006, + "duration": 0.0945393294095993, + "depth": 0.0009462718735449016, + "SDE": 6.218545663851509, + "chi2_min": 19990.264594072247 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004929786082357168, + "SDE": 13.82952668342654, + "chi2_min": 20035.94592072764 + }, + { + "injected": false, + "period": 13.100994110107422, + "T0": 0.15181724491853288, + "duration": 0.37815743684768677, + "depth": 0.00040304477442987263, + "SDE": 5.412653048702645, + "chi2_min": 19320.924473307685 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004904397297650576, + "SDE": 14.709911967208317, + "chi2_min": 19659.042140022346 + }, + { + "injected": false, + "period": 2.640021324157715, + "T0": 0.49285268476407396, + "duration": 0.07459786534309387, + "depth": 0.00045013066846877337, + "SDE": 6.37912014455607, + "chi2_min": 19592.601715390534 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0048844218254089355, + "SDE": 14.631184017496109, + "chi2_min": 19840.06441198555 + }, + { + "injected": false, + "period": 9.71132755279541, + "T0": 1.684317547055585, + "duration": 0.07749367505311966, + "depth": 0.0007628701278008521, + "SDE": 4.643142154034844, + "chi2_min": 20047.546487266438 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.3101788923334254, + "duration": 0.17484456300735474, + "depth": 0.004847844131290913, + "SDE": 14.170468105466723, + "chi2_min": 19459.394237877423 + }, + { + "injected": false, + "period": 1.5595471858978271, + "T0": 0.281584903400649, + "duration": 0.06259265542030334, + "depth": 0.00035733776167035103, + "SDE": 6.133569932837978, + "chi2_min": 19450.04878659191 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.00494115287438035, + "SDE": 14.934345918656119, + "chi2_min": 19811.90842999346 + }, + { + "injected": false, + "period": 3.7597527503967285, + "T0": 3.5487965172173404, + "duration": 0.08818858861923218, + "depth": 0.0005031783948652446, + "SDE": 4.845939359134309, + "chi2_min": 19562.621872353666 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0048937126994132996, + "SDE": 14.346971868723235, + "chi2_min": 19681.977688665196 + }, + { + "injected": false, + "period": 5.938205242156982, + "T0": 1.8585079530804478, + "duration": 0.0977407768368721, + "depth": 0.0006222114316187799, + "SDE": 5.532715469680132, + "chi2_min": 19645.132535764733 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004818635061383247, + "SDE": 14.640026979696545, + "chi2_min": 19860.658444655222 + }, + { + "injected": false, + "period": 0.6239511370658875, + "T0": 0.1721244509631692, + "duration": 0.03426845371723175, + "depth": 0.00033038845867849886, + "SDE": 7.0807451820863845, + "chi2_min": 19813.219665817196 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.0048765623942017555, + "SDE": 14.628734025382231, + "chi2_min": 19747.14876100597 + }, + { + "injected": false, + "period": 4.556577205657959, + "T0": 3.351539513559203, + "duration": 0.09879637509584427, + "depth": 0.00046747003216296434, + "SDE": 5.8276992197673065, + "chi2_min": 19887.865550761333 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.00508846715092659, + "SDE": 14.84249018474726, + "chi2_min": 19832.461552269273 + }, + { + "injected": false, + "period": 1.7158273458480835, + "T0": 0.7026321212040472, + "duration": 0.04569127783179283, + "depth": 0.0004081173974554986, + "SDE": 4.770439070682372, + "chi2_min": 19686.11071394511 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005101200193166733, + "SDE": 15.04480815336938, + "chi2_min": 20083.27710137617 + }, + { + "injected": false, + "period": 1.944218635559082, + "T0": 1.0748527127935859, + "duration": 0.04533376544713974, + "depth": 0.0004777288413606584, + "SDE": 6.197533313519624, + "chi2_min": 19727.02577046268 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005103249568492174, + "SDE": 14.776355510397183, + "chi2_min": 19878.123486338805 + }, + { + "injected": false, + "period": 5.355508804321289, + "T0": 1.199133642505899, + "duration": 0.09922617673873901, + "depth": 0.0006026808405295014, + "SDE": 5.162988651305213, + "chi2_min": 19456.848130541075 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004868575371801853, + "SDE": 14.538692492650142, + "chi2_min": 19636.010256951173 + }, + { + "injected": false, + "period": 0.8417149186134338, + "T0": 0.668898175097727, + "duration": 0.04615739732980728, + "depth": 0.0003474026161711663, + "SDE": 6.254640973283194, + "chi2_min": 19683.038635781624 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004774271510541439, + "SDE": 14.513693414179459, + "chi2_min": 19636.113575339034 + }, + { + "injected": false, + "period": 2.132042646408081, + "T0": 1.8807319745508266, + "duration": 0.051615022122859955, + "depth": 0.0004840661713387817, + "SDE": 5.2538700697855205, + "chi2_min": 19577.356464267443 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004903943277895451, + "SDE": 14.392462830205792, + "chi2_min": 19423.792086657333 + }, + { + "injected": false, + "period": 2.433090925216675, + "T0": 2.2493649780494422, + "duration": 0.11910539865493774, + "depth": 0.00037549060652963817, + "SDE": 6.827777238599113, + "chi2_min": 19900.991971154217 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004682204220443964, + "SDE": 14.010258965609918, + "chi2_min": 20204.227365926825 + }, + { + "injected": false, + "period": 9.213768005371094, + "T0": 3.037360770377745, + "duration": 0.0840730294585228, + "depth": 0.0007720250287093222, + "SDE": 5.165652201639094, + "chi2_min": 19451.32359980548 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004808785393834114, + "SDE": 14.815688328967624, + "chi2_min": 19650.37283534435 + }, + { + "injected": false, + "period": 8.733040809631348, + "T0": 1.2241375973440398, + "duration": 0.07479896396398544, + "depth": 0.0008323907968588173, + "SDE": 5.432235623151964, + "chi2_min": 19882.748090532048 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004958319012075663, + "SDE": 14.562404975680403, + "chi2_min": 19647.290293328322 + }, + { + "injected": false, + "period": 0.6907184720039368, + "T0": 0.5337274346762655, + "duration": 0.03544960170984268, + "depth": 0.0003173367877025157, + "SDE": 7.927425804810807, + "chi2_min": 19180.72897106255 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004934984724968672, + "SDE": 14.786869629495767, + "chi2_min": 19821.351968808078 + }, + { + "injected": false, + "period": 1.7158273458480835, + "T0": 1.436677274974798, + "duration": 0.07134322077035904, + "depth": 0.00036875662044622004, + "SDE": 7.296099190818101, + "chi2_min": 19453.75529417677 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004847510252147913, + "SDE": 14.78850613901599, + "chi2_min": 20212.399796019814 + }, + { + "injected": false, + "period": 4.487700462341309, + "T0": 1.568976793495409, + "duration": 0.06614834815263748, + "depth": 0.0006190845742821693, + "SDE": 5.294980863061793, + "chi2_min": 19581.16770233867 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004917678888887167, + "SDE": 14.863112032456096, + "chi2_min": 19816.37478916323 + }, + { + "injected": false, + "period": 0.8550297021865845, + "T0": 0.39220515779566156, + "duration": 0.038063161075115204, + "depth": 0.0003480055893305689, + "SDE": 4.981027191056973, + "chi2_min": 19780.845065616708 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004977596458047628, + "SDE": 14.722472150541336, + "chi2_min": 19689.09371525447 + }, + { + "injected": false, + "period": 1.7699131965637207, + "T0": 1.466499523809091, + "duration": 0.04850965365767479, + "depth": 0.0004770091036334634, + "SDE": 6.181892254357935, + "chi2_min": 19889.050656765903 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004852476995438337, + "SDE": 14.651176792889993, + "chi2_min": 19782.216123334554 + }, + { + "injected": false, + "period": 1.6712085008621216, + "T0": 0.23874408222442334, + "duration": 0.05254431068897247, + "depth": 0.00042131132795475423, + "SDE": 6.297867326815318, + "chi2_min": 19369.96945911215 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.005023227538913488, + "SDE": 14.57819501444377, + "chi2_min": 19689.35071630928 + }, + { + "injected": false, + "period": 0.9706023335456848, + "T0": 0.952585647599431, + "duration": 0.07192564755678177, + "depth": 0.00028235651552677155, + "SDE": 5.854673361596672, + "chi2_min": 20023.695400763077 + }, + { + "injected": true, + "period": 7.696986198425293, + "T0": 2.315746140649111, + "duration": 0.17484456300735474, + "depth": 0.004857673309743404, + "SDE": 14.150109315731994, + "chi2_min": 19449.491679204788 + }, + { + "injected": false, + "period": 8.042945861816406, + "T0": 3.4846562324514707, + "duration": 0.07646815478801727, + "depth": 0.0008291943813674152, + "SDE": 5.126222758428061, + "chi2_min": 19774.037059029462 + } + ] + } + } + }, + "tess-yr": { + "config": { + "ndata": 16850, + "baseline": 351.0, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 21.7, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 175.0, + "nlc": 20 + }, + "nlc": 20, + "nperiods": 42001, + "impls": { + "new": { + "nlc": 20, + "total_s": 0.34016153216362, + "times_s": [ + 0.34016153216362 + ], + "ms_per_lc": 17.008076608181, + "lc_per_s": 58.795595941694735, + "n_injected": 10, + "n_recovered": 10, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 53.27684286723869, + "median_sde_noise": 8.475549940896691, + "per_lc": [ + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.003985285758972168, + "SDE": 52.52794267307139, + "chi2_min": 17032.804161600427 + }, + { + "injected": false, + "period": 77.67776489257812, + "T0": 7.999921420467899, + "duration": 0.2542693614959717, + "depth": 0.0007119004148989916, + "SDE": 7.88728480150725, + "chi2_min": 16854.908607090067 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.00401003472507, + "SDE": 54.354682131569625, + "chi2_min": 17070.743693423847 + }, + { + "injected": false, + "period": 55.14839553833008, + "T0": 52.78218937309475, + "duration": 0.2268328219652176, + "depth": 0.0006788634927943349, + "SDE": 6.475408867465852, + "chi2_min": 16564.201440459707 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004078013356775045, + "SDE": 52.35457710087205, + "chi2_min": 16669.709582001655 + }, + { + "injected": false, + "period": 115.44019317626953, + "T0": 40.610479753671825, + "duration": 0.19526782631874084, + "depth": 0.0010937515180557966, + "SDE": 9.289476895165315, + "chi2_min": 16943.432229490376 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.003973984159529209, + "SDE": 54.03703866575641, + "chi2_min": 16946.253189404146 + }, + { + "injected": false, + "period": 6.136112213134766, + "T0": 3.792819025809422, + "duration": 0.06987259536981583, + "depth": 0.0004311114316806197, + "SDE": 8.584658625062868, + "chi2_min": 16616.814742018563 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004104473162442446, + "SDE": 53.55619974408649, + "chi2_min": 17065.533314418266 + }, + { + "injected": false, + "period": 1.0810301303863525, + "T0": 0.8323784887314218, + "duration": 0.03727799281477928, + "depth": 0.0002662955957930535, + "SDE": 11.62929676085854, + "chi2_min": 16806.166494044795 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.0038824535440653563, + "SDE": 52.557725691364844, + "chi2_min": 17112.30436619236 + }, + { + "injected": false, + "period": 35.86662292480469, + "T0": 3.5118320590913754, + "duration": 0.17800024151802063, + "depth": 0.0006325138383544981, + "SDE": 7.3888615817912315, + "chi2_min": 16643.5253821164 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004052670206874609, + "SDE": 53.70233039426787, + "chi2_min": 17360.095233849726 + }, + { + "injected": false, + "period": 105.29816436767578, + "T0": 18.38559195387313, + "duration": 0.18937286734580994, + "depth": 0.0009571330738253891, + "SDE": 8.366441256730516, + "chi2_min": 17168.121176113866 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004038219340145588, + "SDE": 52.99748599039089, + "chi2_min": 17052.555723155958 + }, + { + "injected": false, + "period": 158.6757354736328, + "T0": 94.3506197494853, + "duration": 0.4794192910194397, + "depth": 0.0008418660727329552, + "SDE": 7.713874966221854, + "chi2_min": 16732.353856341557 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004093342926353216, + "SDE": 53.73570147653968, + "chi2_min": 17013.570022694264 + }, + { + "injected": false, + "period": 143.65647888183594, + "T0": 105.67623106332121, + "duration": 0.1902312934398651, + "depth": 0.001477456884458661, + "SDE": 8.895018055638662, + "chi2_min": 16926.715160293177 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.0040013594552874565, + "SDE": 52.06098131238311, + "chi2_min": 16767.923550105537 + }, + { + "injected": false, + "period": 1.0684576034545898, + "T0": 0.9397277924298919, + "duration": 0.04099808633327484, + "depth": 0.0002517042157705873, + "SDE": 10.026241554881262, + "chi2_min": 16825.25249206514 + } + ] + } + } + }, + "kepler-4yr": { + "config": { + "ndata": 65440, + "baseline": 1363.0, + "cadence": 0.020833333333333332, + "noise": 0.0006, + "inject_period": 41.3, + "inject_depth": 0.003, + "period_min": 0.6, + "period_max": 500.0, + "nlc": 10 + }, + "nlc": 10, + "nperiods": 171688, + "impls": { + "new": { + "nlc": 10, + "total_s": 1.4650629945099354, + "times_s": [ + 1.4650629945099354 + ], + "ms_per_lc": 146.50629945099354, + "lc_per_s": 6.82564506609834, + "n_injected": 5, + "n_recovered": 5, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 102.31244744721329, + "median_sde_noise": 8.48757577323759, + "per_lc": [ + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0030894107185304165, + "SDE": 102.40051303208178, + "chi2_min": 65543.0815030234 + }, + { + "injected": false, + "period": 55.92778396606445, + "T0": 50.18960453722707, + "duration": 0.16932646930217743, + "depth": 0.00028693469357676804, + "SDE": 8.48757577323759, + "chi2_min": 65560.16814887687 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003081277944147587, + "SDE": 104.30749291660592, + "chi2_min": 65923.97301494204 + }, + { + "injected": false, + "period": 253.2958526611328, + "T0": 196.6530496462574, + "duration": 0.3961925506591797, + "depth": 0.0003831548965536058, + "SDE": 8.290345844723038, + "chi2_min": 65907.63152056489 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003086133161559701, + "SDE": 100.93630112578315, + "chi2_min": 65833.95628749099 + }, + { + "injected": false, + "period": 96.05792236328125, + "T0": 50.60741073171448, + "duration": 0.2027805745601654, + "depth": 0.0003557393793016672, + "SDE": 11.321606242738845, + "chi2_min": 65324.45621736963 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0031173741444945335, + "SDE": 101.93700097570971, + "chi2_min": 65971.8080052495 + }, + { + "injected": false, + "period": 164.4737091064453, + "T0": 46.61144217862193, + "duration": 0.19900889694690704, + "depth": 0.00041615593363530934, + "SDE": 7.8630042377815, + "chi2_min": 65834.0297949983 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0030800634995102882, + "SDE": 102.31244744721329, + "chi2_min": 66320.43199575332 + }, + { + "injected": false, + "period": 2.184530735015869, + "T0": 1.369407355578943, + "duration": 0.10407035797834396, + "depth": 6.97811265126802e-05, + "SDE": 9.845653250598026, + "chi2_min": 65124.53212548583 + } + ] + } + } + } + }, + "env": { + "python": "3.11.10", + "numpy": "2.4.6", + "hostname": "2c893c3df85f", + "cpu_count": 80, + "cuvarbase": "1.0.0", + "pycuda": "2026.1", + "cuda_driver_version": 12040, + "gpu": "Tesla V100-SXM2-16GB", + "compute_capability": "7.0", + "nvcc": "Cuda compilation tools, release 12.4, V12.4.131" + } +} \ No newline at end of file diff --git a/benchmarks/results/tls_survey_jul2026/tls_survey_v100b.json b/benchmarks/results/tls_survey_jul2026/tls_survey_v100b.json new file mode 100644 index 0000000..78d752b --- /dev/null +++ b/benchmarks/results/tls_survey_jul2026/tls_survey_v100b.json @@ -0,0 +1,367 @@ +{ + "script": "benchmark_tls_survey.py", + "timestamp": "2026-07-06T18:20:57", + "args": { + "regimes": "kepler-4yr,tess-yr", + "nlc": null, + "impls": "new", + "ref_nlc": 1, + "old_nlc": 5, + "n_iter": 1, + "output": "tls_survey_v100b.json", + "quick": false, + "ref_all": false + }, + "regimes": { + "kepler-4yr": { + "config": { + "ndata": 65440, + "baseline": 1363.0, + "cadence": 0.020833333333333332, + "noise": 0.0006, + "inject_period": 41.3, + "inject_depth": 0.003, + "period_min": 0.6, + "period_max": 500.0, + "nlc": 10 + }, + "nlc": 10, + "nperiods": 171688, + "impls": { + "new": { + "nlc": 10, + "total_s": 1.4562256298959255, + "times_s": [ + 1.4562256298959255 + ], + "ms_per_lc": 145.62256298959255, + "lc_per_s": 6.86706770894747, + "n_injected": 5, + "n_recovered": 5, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 102.31244754205247, + "median_sde_noise": 8.48757579072466, + "per_lc": [ + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0030894107185304165, + "SDE": 102.4005130679425, + "chi2_min": 65543.0815030234 + }, + { + "injected": false, + "period": 55.92778396606445, + "T0": 50.18960453722707, + "duration": 0.16932646930217743, + "depth": 0.00028693469357676804, + "SDE": 8.48757579072466, + "chi2_min": 65560.16814887687 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003081277944147587, + "SDE": 104.30749300460378, + "chi2_min": 65923.97301494204 + }, + { + "injected": false, + "period": 253.2958526611328, + "T0": 196.6530496462574, + "duration": 0.3961925506591797, + "depth": 0.0003831548965536058, + "SDE": 8.290345864402228, + "chi2_min": 65907.63152056489 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.003086133161559701, + "SDE": 100.93630122077218, + "chi2_min": 65833.95628749099 + }, + { + "injected": false, + "period": 96.05792236328125, + "T0": 50.60741073171448, + "duration": 0.2027805745601654, + "depth": 0.0003557393793016672, + "SDE": 11.321606292828855, + "chi2_min": 65324.45621736963 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0031173741444945335, + "SDE": 101.93700022710857, + "chi2_min": 65971.8080052495 + }, + { + "injected": false, + "period": 164.4737091064453, + "T0": 46.61144217862193, + "duration": 0.19900889694690704, + "depth": 0.00041615593363530934, + "SDE": 7.863004249934092, + "chi2_min": 65834.0297949983 + }, + { + "injected": true, + "period": 41.30036926269531, + "T0": 12.382114458711385, + "duration": 0.2772420048713684, + "depth": 0.0030800634995102882, + "SDE": 102.31244754205247, + "chi2_min": 66320.43199575332 + }, + { + "injected": false, + "period": 2.184530735015869, + "T0": 1.369407355578943, + "duration": 0.10407035797834396, + "depth": 6.97811265126802e-05, + "SDE": 9.845653212100956, + "chi2_min": 65124.53212548583 + } + ] + } + } + }, + "tess-yr": { + "config": { + "ndata": 16850, + "baseline": 351.0, + "cadence": 0.020833333333333332, + "noise": 0.001, + "inject_period": 21.7, + "inject_depth": 0.004, + "period_min": 0.6, + "period_max": 175.0, + "nlc": 20 + }, + "nlc": 20, + "nperiods": 42001, + "impls": { + "new": { + "nlc": 20, + "total_s": 0.3298470973968506, + "times_s": [ + 0.3298470973968506 + ], + "ms_per_lc": 16.49235486984253, + "lc_per_s": 60.63415490947098, + "n_injected": 10, + "n_recovered": 10, + "n_alias": 0, + "recovery_frac": 1.0, + "median_sde_injected": 53.27684294213596, + "median_sde_noise": 8.475549912415742, + "per_lc": [ + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.003985285758972168, + "SDE": 52.52794280298104, + "chi2_min": 17032.804161600427 + }, + { + "injected": false, + "period": 77.67776489257812, + "T0": 7.999921420467899, + "duration": 0.2542693614959717, + "depth": 0.0007119004148989916, + "SDE": 7.887282337040116, + "chi2_min": 16854.908607090067 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.00401003472507, + "SDE": 54.35468226435136, + "chi2_min": 17070.743693423847 + }, + { + "injected": false, + "period": 55.14839553833008, + "T0": 52.78218937309475, + "duration": 0.2268328219652176, + "depth": 0.0006788634927943349, + "SDE": 6.4754088282884315, + "chi2_min": 16564.201440459707 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004078013356775045, + "SDE": 52.354577062494386, + "chi2_min": 16669.709582001655 + }, + { + "injected": false, + "period": 115.44019317626953, + "T0": 40.610479753671825, + "duration": 0.19526782631874084, + "depth": 0.0010937515180557966, + "SDE": 9.289476498694379, + "chi2_min": 16943.432229490376 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.003973984159529209, + "SDE": 54.03703867483079, + "chi2_min": 16946.253189404146 + }, + { + "injected": false, + "period": 6.136112213134766, + "T0": 3.792819025809422, + "duration": 0.06987259536981583, + "depth": 0.0004311114316806197, + "SDE": 8.584658587227791, + "chi2_min": 16616.814742018563 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004104473162442446, + "SDE": 53.556199795622724, + "chi2_min": 17065.533314418266 + }, + { + "injected": false, + "period": 1.0810301303863525, + "T0": 0.8323784887314218, + "duration": 0.03727799281477928, + "depth": 0.0002662955957930535, + "SDE": 11.62930028802867, + "chi2_min": 16806.166494044795 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.0038824535440653563, + "SDE": 52.557725468536425, + "chi2_min": 17112.30436619236 + }, + { + "injected": false, + "period": 35.86662292480469, + "T0": 3.5118320590913754, + "duration": 0.17800024151802063, + "depth": 0.0006325138383544981, + "SDE": 7.388861608999988, + "chi2_min": 16643.5253821164 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004052670206874609, + "SDE": 53.70233035497617, + "chi2_min": 17360.095233849726 + }, + { + "injected": false, + "period": 105.29816436767578, + "T0": 18.38559195387313, + "duration": 0.18937286734580994, + "depth": 0.0009571330738253891, + "SDE": 8.366441237603693, + "chi2_min": 17168.121176113866 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004038219340145588, + "SDE": 52.99748608864919, + "chi2_min": 17052.555723155958 + }, + { + "injected": false, + "period": 158.6757354736328, + "T0": 94.3506197494853, + "duration": 0.4794192910194397, + "depth": 0.0008418660727329552, + "SDE": 7.713874971628795, + "chi2_min": 16732.353856341557 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.004093342926353216, + "SDE": 53.735701438061646, + "chi2_min": 17013.570022694264 + }, + { + "injected": false, + "period": 143.65647888183594, + "T0": 105.67623106332121, + "duration": 0.1902312934398651, + "depth": 0.001477456884458661, + "SDE": 8.895017997469333, + "chi2_min": 16926.715160293177 + }, + { + "injected": true, + "period": 21.701496124267578, + "T0": 6.495490946717155, + "duration": 0.235074982047081, + "depth": 0.0040013594552874565, + "SDE": 52.06098135221865, + "chi2_min": 16767.923550105537 + }, + { + "injected": false, + "period": 1.0684576034545898, + "T0": 0.9397277924298919, + "duration": 0.04099808633327484, + "depth": 0.0002517042157705873, + "SDE": 10.02623970261992, + "chi2_min": 16825.25249206514 + } + ] + } + } + } + }, + "env": { + "python": "3.11.10", + "numpy": "2.4.6", + "hostname": "2c893c3df85f", + "cpu_count": 80, + "cuvarbase": "1.0.0", + "pycuda": "2026.1", + "cuda_driver_version": 12040, + "gpu": "Tesla V100-SXM2-16GB", + "compute_capability": "7.0", + "nvcc": "Cuda compilation tools, release 12.4, V12.4.131" + } +} \ No newline at end of file diff --git a/cuvarbase/kernels/tls_fast.cu b/cuvarbase/kernels/tls_fast.cu new file mode 100644 index 0000000..26a147e --- /dev/null +++ b/cuvarbase/kernels/tls_fast.cu @@ -0,0 +1,576 @@ +/* + * Fast Transit Least Squares (TLS) GPU kernel — batch-native. + * + * Algorithmic differences from tls.cu (the reference kernel): + * + * 1. Closed-form chi2. For the weighted least-squares transit fit with + * template T and depth d, chi2(d) = chi2_0 - 2 d num + d^2 den with + * num = sum_i (1 - y_i) T_i / sigma_i^2 + * den = sum_i T_i^2 / sigma_i^2 + * chi2_0 = sum_i (y_i - 1)^2 / sigma_i^2 (per-lightcurve constant) + * At the optimal depth d* = num/den, chi2 = chi2_0 - num^2/den, so a + * single accumulation pass yields both the depth and the chi2 — the + * reference kernel's second full-data chi2 pass is redundant. + * Minimizing chi2 over trials is exactly maximizing num^2/den, so the + * per-period argmin never suffers cancellation against chi2_0. + * + * 2. Phase-binned evaluation. Each block folds its lightcurve at its + * period ONCE into NBINS phase bins (A_k = sum (1-y)/sigma^2, + * B_k = sum 1/sigma^2), then every (duration, t0) trial integrates + * only the ~q*NBINS bins inside the transit window instead of + * scanning all ndata points. This removes both the O(ndata) factor + * from the trial loop and the shared-memory cap on ndata (raw data + * stay in global memory and are read exactly once per period). + * + * 3. Integrated template tables. S1(x) = int_{-1}^{x} T dx and + * S2(x) = int_{-1}^{x} T^2 dx are precomputed on the CPU + * (tls_models.generate_template_integrals). The bin-averaged + * template over a bin's transit-coordinate span [c0, c1] is + * (S1(c1)-S1(c0))/(c1-c0): area sampling rather than point + * sampling, so coarse bins (few bins per duration) remain accurate. + * + * 4. Batch-native. Grid is (nperiods, nlc); per-lightcurve data are + * concatenated with offset/length arrays. A whole survey chunk is a + * single kernel launch sharing one period grid and one template. + * + * The (duration, t0) trial grid is IDENTICAL to tls.cu: n_durations + * log-spaced durations in [qmin, qmax], t0 = j/n_t0 with + * n_t0 = clamp(ceil(T0_OVERSAMPLE/q), MIN_N_T0, MAX_N_T0), and the + * same validity gate 0 < depth < 0.5. + * + * References: + * [1] Hippke & Heller (2019), A&A 623, A39 + * [2] Kovacs et al. (2002), A&A 391, 369 + */ + +#include + +//{CPP_DEFS} + +#ifndef BLOCK_SIZE +#define BLOCK_SIZE 128 +#endif + +/* Number of phase bins; must be a power of two (wrap uses a mask). */ +#ifndef NBINS +#define NBINS 2048 +#endif + +/* Number of intervals in the integrated template tables (tables have + * NTEMPLATE+1 entries). Must match the Python-side table length. */ +#ifndef NTEMPLATE +#define NTEMPLATE 1024 +#endif + +/* Maximum n_durations supported by the per-duration shared staging. */ +#ifndef MAX_DURATIONS +#define MAX_DURATIONS 64 +#endif + +/* Number of local durations scanned by the refinement kernel (odd). */ +#ifndef REFINE_ND +#define REFINE_ND 3 +#endif + +#ifndef T0_OVERSAMPLE +#define T0_OVERSAMPLE 3.0f +#endif +#ifndef MIN_N_T0 +#define MIN_N_T0 30 +#endif +#ifndef MAX_N_T0 +#define MAX_N_T0 20000 +#endif + +#define WARP_SIZE 32 + +__device__ inline float mod1f(float x) { + return x - floorf(x); +} + +__device__ inline int t0_grid_size(float duration_phase) { + int n_t0 = (int)ceilf(T0_OVERSAMPLE / duration_phase); + if (n_t0 < MIN_N_T0) n_t0 = MIN_N_T0; + if (n_t0 > MAX_N_T0) n_t0 = MAX_N_T0; + return n_t0; +} + +/* + * Evaluate an integrated table S (NTEMPLATE+1 entries spanning + * x in [-1, 1]) at x, with linear interpolation. Outside [-1, 1] the + * template is zero, so S saturates at its endpoint values. + */ +__device__ inline float lookup_integral(const float* __restrict__ S, float x) +{ + float idx_f = (x + 1.0f) * (0.5f * (float)NTEMPLATE); + idx_f = fminf(fmaxf(idx_f, 0.0f), (float)NTEMPLATE); + int i0 = (int)idx_f; + if (i0 >= NTEMPLATE) i0 = NTEMPLATE - 1; + float frac = idx_f - (float)i0; + return S[i0] + (S[i0 + 1] - S[i0]) * frac; +} + +/* + * Fast TLS search kernel (batch-native, Keplerian duration constraints). + * + * Grid: (nperiods, nlc, 1); Block: (BLOCK_SIZE, 1, 1) + * + * Inputs (global memory): + * t_hi_all, t_lo_all, a_all, b_all : concatenated per-point arrays; + * t is stored as an epoch-subtracted float-float pair + * (t = t_hi + t_lo to float64 precision), and for point i, + * a = (1 - y)/sigma^2 and b = 1/sigma^2 + * (sigma^2 includes the +1e-10 regularizer, matching tls.cu) + * lc_off, lc_len : per-lightcurve offset/length into the above + * periods[nperiods_band], qmin[...], qmax[...] : the trial grid FOR + * THIS LAUNCH. The host may split the full grid into bands that + * compile with different NBINS (narrow durations need finer + * bins; the scan cost is proportional to NBINS, so coarse bands + * should not pay the finest band's price). + * period_map[nperiods_band] : global period index of each band entry + * (identity when the grid is not banded) + * S1, S2 : integrated template tables (NTEMPLATE+1 entries each) + * + * Outputs, laid out as [lc * nperiods_total + period_map[band idx]]: + * score_out (num^2/den = chi2_0 - chi2; <= 0 marks a failed period; + * the host reconstructs chi2 in float64), best_t0_out, + * best_duration_out, best_depth_out + * + * Shared memory layout (floats): + * A[NBINS] | B[NBINS] | S1[NTEMPLATE+1] | S2[NTEMPLATE+1] | + * red_score[BLOCK_SIZE] | red_t0[BLOCK_SIZE] | red_dur[BLOCK_SIZE] | + * red_depth[BLOCK_SIZE] | dur_q[MAX_DURATIONS] | dur_cum[MAX_DURATIONS+1] + */ +extern "C" __global__ void tls_fast_search_kernel( + const float* __restrict__ t_hi_all, + const float* __restrict__ t_lo_all, + const float* __restrict__ a_all, + const float* __restrict__ b_all, + const int* __restrict__ lc_off, + const int* __restrict__ lc_len, + const float* __restrict__ periods, + const float* __restrict__ qmin, + const float* __restrict__ qmax, + const int* __restrict__ period_map, + const float* __restrict__ S1_g, + const float* __restrict__ S2_g, + const int nperiods_band, + const int nperiods_total, + const int n_durations, + float* __restrict__ score_out, + float* __restrict__ best_t0_out, + float* __restrict__ best_duration_out, + float* __restrict__ best_depth_out) +{ + extern __shared__ float shared_mem[]; + float* A = shared_mem; + float* B = &A[NBINS]; + float* S1 = &B[NBINS]; + float* S2 = &S1[NTEMPLATE + 1]; + float* red_score = &S2[NTEMPLATE + 1]; + float* red_t0 = &red_score[BLOCK_SIZE]; + float* red_dur = &red_t0[BLOCK_SIZE]; + float* red_depth = &red_dur[BLOCK_SIZE]; + float* dur_q = &red_depth[BLOCK_SIZE]; + /* trial-index prefix sums per duration (stored as float-cast ints + * would lose precision above 2^24; keep a separate int view) */ + int* dur_cum = (int*)&dur_q[MAX_DURATIONS]; + + const int period_idx = blockIdx.x; + const int lc_idx = blockIdx.y; + if (period_idx >= nperiods_band) return; + + const int off = lc_off[lc_idx]; + const int nd = lc_len[lc_idx]; + const float period = periods[period_idx]; + + /* --- Stage integrated template tables and zero the bins --- */ + for (int i = threadIdx.x; i < NTEMPLATE + 1; i += blockDim.x) { + S1[i] = S1_g[i]; + S2[i] = S2_g[i]; + } + for (int i = threadIdx.x; i < NBINS; i += blockDim.x) { + A[i] = 0.0f; + B[i] = 0.0f; + } + + /* --- Per-duration trial bookkeeping (one thread; tiny) --- */ + if (threadIdx.x == 0) { + float lqmin = logf(qmin[period_idx]); + float lqmax = logf(qmax[period_idx]); + int cum = 0; + for (int d = 0; d < n_durations; d++) { + float lq = (n_durations > 1) + ? lqmin + (lqmax - lqmin) * d / (n_durations - 1) + : lqmin; + float q = expf(lq); + dur_q[d] = q; + dur_cum[d] = cum; + cum += t0_grid_size(q); + } + dur_cum[n_durations] = cum; + } + __syncthreads(); + + /* --- Fold and bin the lightcurve at this period --- + * Float-float ("double-single") fold: at plain float32, t/P for a + * 1,400-day baseline and a short period carries a phase error of + * ~1e-4 — the size of a whole bin. Times are stored as a hi/lo + * float32 pair (t = t_hi + t_lo exactly to float64 precision) and + * the period reciprocal is split the same way, so the fractional + * phase is recovered to ~1e-7 with pure FP32 FMAs. This avoids + * double-precision math, which runs at 1/64 rate on consumer GPUs + * and would otherwise dominate the whole kernel at large ndata. */ + const double inv_period_d = 1.0 / (double)period; + const float inv_hi = (float)inv_period_d; + const float inv_lo = (float)(inv_period_d - (double)inv_hi); + for (int i = threadIdx.x; i < nd; i += blockDim.x) { + const float th = t_hi_all[off + i]; + const float tl = t_lo_all[off + i]; + float u = th * inv_hi; + float e = fmaf(th, inv_hi, -u); /* exact product residual */ + float c = fmaf(th, inv_lo, fmaf(tl, inv_hi, e)); + float phi = (u - floorf(u)) + c; + phi -= floorf(phi); + int k = (int)(phi * (float)NBINS); + k &= (NBINS - 1); + atomicAdd(&A[k], a_all[off + i]); + atomicAdd(&B[k], b_all[off + i]); + } + __syncthreads(); + + const int total_trials = dur_cum[n_durations]; + + /* --- Scan all (duration, t0) trials, flattened across threads --- */ + float best_score = -1.0f; /* score = num^2/den = chi2_0 - chi2 */ + float best_t0 = 0.0f; + float best_dur = 0.0f; + float best_depth = 0.0f; + + int d_idx = 0; + for (int trial = threadIdx.x; trial < total_trials; trial += blockDim.x) { + /* locate the duration bucket (monotonically increasing) */ + while (dur_cum[d_idx + 1] <= trial) d_idx++; + + const float q = dur_q[d_idx]; + const float hd = 0.5f * q; + const float inv_hd = 1.0f / hd; + const int n_t0 = dur_cum[d_idx + 1] - dur_cum[d_idx]; + const int t0_idx = trial - dur_cum[d_idx]; + const float t0 = (float)t0_idx / (float)n_t0; + + /* bins overlapping the window [t0 - hd, t0 + hd] */ + const float invNB = 1.0f / (float)NBINS; + int k0 = (int)floorf((t0 - hd) * (float)NBINS); + int k1 = (int)ceilf((t0 + hd) * (float)NBINS) - 1; + /* q >= 1 is rejected host-side; belt-and-braces so a rogue + * window can never visit a bin twice */ + if (k1 - k0 >= NBINS) k1 = k0 + NBINS - 1; + + /* transit coordinate of bin kk's left edge, and per-bin span */ + const float dc = invNB * inv_hd; + + float num = 0.0f; + float den = 0.0f; + float c0 = ((float)k0 * invNB - t0) * inv_hd; + float s1_prev = lookup_integral(S1, c0); + float s2_prev = lookup_integral(S2, c0); + for (int kk = k0; kk <= k1; kk++) { + int k = kk & (NBINS - 1); + float c1 = c0 + dc; + float s1_next = lookup_integral(S1, c1); + float s2_next = lookup_integral(S2, c1); + num += A[k] * (s1_next - s1_prev); + den += B[k] * (s2_next - s2_prev); + s1_prev = s1_next; + s2_prev = s2_next; + c0 = c1; + } + /* bin-average scale: 1/(c1-c0) = hd*NBINS applied once */ + const float scale = hd * (float)NBINS; + num *= scale; + den *= scale; + + if (den > 1e-10f && num > 0.0f) { + float depth = num / den; + if (depth < 0.5f) { + float score = num * depth; /* num^2/den */ + if (score > best_score) { + best_score = score; + best_t0 = t0; + best_dur = q * period; + best_depth = depth; + } + } + } + } + + /* --- Block reduction (max score) --- */ + red_score[threadIdx.x] = best_score; + red_t0[threadIdx.x] = best_t0; + red_dur[threadIdx.x] = best_dur; + red_depth[threadIdx.x] = best_depth; + __syncthreads(); + + for (int stride = blockDim.x / 2; stride >= WARP_SIZE; stride /= 2) { + if (threadIdx.x < stride) { + if (red_score[threadIdx.x + stride] > red_score[threadIdx.x]) { + red_score[threadIdx.x] = red_score[threadIdx.x + stride]; + red_t0[threadIdx.x] = red_t0[threadIdx.x + stride]; + red_dur[threadIdx.x] = red_dur[threadIdx.x + stride]; + red_depth[threadIdx.x] = red_depth[threadIdx.x + stride]; + } + } + __syncthreads(); + } + + if (threadIdx.x < WARP_SIZE) { + float v_score = red_score[threadIdx.x]; + float v_t0 = red_t0[threadIdx.x]; + float v_dur = red_dur[threadIdx.x]; + float v_dep = red_depth[threadIdx.x]; + + for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) { + float o_score = __shfl_down_sync(0xffffffff, v_score, offset); + float o_t0 = __shfl_down_sync(0xffffffff, v_t0, offset); + float o_dur = __shfl_down_sync(0xffffffff, v_dur, offset); + float o_dep = __shfl_down_sync(0xffffffff, v_dep, offset); + if (o_score > v_score) { + v_score = o_score; + v_t0 = o_t0; + v_dur = o_dur; + v_dep = o_dep; + } + } + + if (threadIdx.x == 0) { + const size_t out_idx = (size_t)lc_idx * nperiods_total + + period_map[period_idx]; + /* Write the SCORE (delta-chi2 = num^2/den = chi2_0 - chi2), + * not chi2 itself: subtracting from the large per-LC + * constant in float32 would quantize the spectrum by + * ulp(chi2_0) ~ 6e-8 * ndata. The host reconstructs + * chi2 = chi2_0 - score in float64. score <= 0 marks a + * period with no valid trial. */ + if (v_score > 0.0f) { + score_out[out_idx] = v_score; + best_t0_out[out_idx] = v_t0; + best_duration_out[out_idx] = v_dur; + best_depth_out[out_idx] = v_dep; + } else { + score_out[out_idx] = -1.0f; + best_t0_out[out_idx] = 0.0f; + best_duration_out[out_idx] = 0.0f; + best_depth_out[out_idx] = 0.0f; + } + } + } +} + +/* + * Exact refinement kernel. + * + * The binned scan quantizes t0 to the bin grid and smears each point's + * template weight over its bin. This kernel re-evaluates the best + * candidate periods per lightcurve EXACTLY (per-point template lookup, + * no binning) on a fine local (duration, t0) grid centered on the + * coarse solution. + * + * Results go to separate compact per-candidate outputs — the coarse + * per-period spectrum is left untouched. Detection statistics (SDE) + * must be computed from a UNIFORM-fidelity spectrum: a finer trial + * grid digs deeper chi2 minima everywhere (noise included), so mixing + * refined values into the coarse spectrum — or refining everything — + * shifts the SR distribution and deflates the SDE scale that the + * legacy kernel and its calibrated thresholds established. Refinement + * therefore only sharpens the best-fit parameters (period choice among + * the candidates, t0, duration, depth, chi2_min). + * + * Grid: (n_candidates, nlc, 1); Block: (BLOCK_SIZE, 1, 1) + * cand_period_idx[lc * n_candidates + c] gives the period index to + * refine (a value < 0 disables that slot). + * + * Trial layout per candidate: REFINE_ND durations log-spaced within + * [q0/dur_span, q0*dur_span] (bracketing one coarse duration-grid + * step), each with n_t0_local epochs spanning +/- t0_halfwidth around + * the coarse t0 at stride q/refine_oversample. + * + * Each trial is owned by one warp-group slice of the block: trials are + * distributed round-robin over (blockDim/WARP_SIZE) warps; a warp + * accumulates num/den over all points with lane-strided reads and + * reduces with shuffles. Points stream from global memory (coalesced); + * the point template T is staged in shared memory. + * + * Shared memory layout (floats): + * T[NTEMPLATE + 1] | warp_best[4 * (BLOCK_SIZE/WARP_SIZE)] + */ +extern "C" __global__ void tls_refine_kernel( + const float* __restrict__ t_hi_all, + const float* __restrict__ t_lo_all, + const float* __restrict__ a_all, + const float* __restrict__ b_all, + const int* __restrict__ lc_off, + const int* __restrict__ lc_len, + const float* __restrict__ periods, + const int* __restrict__ cand_period_idx, + const float* __restrict__ T_g, + const int nperiods, + const int n_candidates, + const float dur_span, /* e.g. one coarse log-step, ~1.10 */ + const float t0_halfwidth_frac, /* halfwidth in units of duration */ + const float refine_oversample, /* t0 stride = q / refine_oversample */ + const float* __restrict__ coarse_t0_in, + const float* __restrict__ coarse_duration_in, + float* __restrict__ refined_score_out, /* [lc * n_candidates + c] */ + float* __restrict__ refined_t0_out, + float* __restrict__ refined_duration_out, + float* __restrict__ refined_depth_out) +{ + extern __shared__ float shared_mem[]; + float* T_sh = shared_mem; + float* warp_best = &T_sh[NTEMPLATE + 1]; /* 4 floats per warp */ + + const int cand_idx = blockIdx.x; + const int lc_idx = blockIdx.y; + if (cand_idx >= n_candidates) return; + + const size_t slot = (size_t)lc_idx * n_candidates + cand_idx; + const int period_idx = cand_period_idx[slot]; + + /* disabled or sentinel candidates still need a sentinel output */ + float coarse_dur = 0.0f, coarse_t0 = 0.0f, period = 1.0f; + if (period_idx >= 0) { + const size_t in_idx = (size_t)lc_idx * nperiods + period_idx; + coarse_dur = coarse_duration_in[in_idx]; + coarse_t0 = coarse_t0_in[in_idx]; + period = periods[period_idx]; + } + if (period_idx < 0 || coarse_dur <= 0.0f) { + if (threadIdx.x == 0) { + refined_score_out[slot] = -1.0f; + refined_t0_out[slot] = 0.0f; + refined_duration_out[slot] = 0.0f; + refined_depth_out[slot] = 0.0f; + } + return; + } + + const int off = lc_off[lc_idx]; + const int nd = lc_len[lc_idx]; + const double inv_period_d = 1.0 / (double)period; + const float inv_hi = (float)inv_period_d; + const float inv_lo = (float)(inv_period_d - (double)inv_hi); + const float q0 = coarse_dur / period; + + for (int i = threadIdx.x; i < NTEMPLATE + 1; i += blockDim.x) { + T_sh[i] = T_g[i]; + } + __syncthreads(); + + const int warp_id = threadIdx.x / WARP_SIZE; + const int lane = threadIdx.x % WARP_SIZE; + const int n_warps = blockDim.x / WARP_SIZE; + + /* local trial grid */ + const float lq0 = logf(q0); + const float ldspan = logf(dur_span); + const int n_dur_local = REFINE_ND; /* compile-time, odd, e.g. 5 */ + + float w_best_score = -1.0f; + float w_best_t0 = 0.0f, w_best_dur = 0.0f, w_best_depth = 0.0f; + + /* count t0 trials for the central duration to fix the grid size + * (same count reused for all durations so trial indexing is flat) */ + const float t0_hw = t0_halfwidth_frac * q0; + const float dt0 = q0 / refine_oversample; + int n_t0_local = 2 * (int)ceilf(t0_hw / dt0) + 1; + + const int total_trials = n_dur_local * n_t0_local; + + for (int trial = warp_id; trial < total_trials; trial += n_warps) { + const int d_i = trial / n_t0_local; + const int t0_i = trial % n_t0_local; + + const float lq = lq0 + ldspan * (2.0f * d_i / (n_dur_local - 1) - 1.0f); + const float q = expf(lq); + const float hd = 0.5f * q; + const float inv_hd = 1.0f / hd; + float t0 = coarse_t0 + dt0 * (float)(t0_i - n_t0_local / 2); + t0 = t0 - floorf(t0); /* wrap to [0, 1) */ + + float num = 0.0f; + float den = 0.0f; + for (int i = lane; i < nd; i += WARP_SIZE) { + const float th = t_hi_all[off + i]; + const float tl = t_lo_all[off + i]; + float u = th * inv_hi; + float e = fmaf(th, inv_hi, -u); + float cc = fmaf(th, inv_lo, fmaf(tl, inv_hi, e)); + float phi = (u - floorf(u)) + cc; + phi -= floorf(phi); + float rel = phi - t0; + rel -= rintf(rel); /* wrap to [-0.5, 0.5] */ + float c = rel * inv_hd; + if (fabsf(c) < 1.0f) { + /* point template lookup (linear interpolation) */ + float idx_f = (c + 1.0f) * (0.5f * (float)NTEMPLATE); + int i0 = (int)idx_f; + if (i0 >= NTEMPLATE) i0 = NTEMPLATE - 1; + float frac = idx_f - (float)i0; + float Tv = T_sh[i0] + (T_sh[i0 + 1] - T_sh[i0]) * frac; + num += a_all[off + i] * Tv; + den += b_all[off + i] * Tv * Tv; + } + } + /* warp reduction of the two partial sums */ + for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) { + num += __shfl_down_sync(0xffffffff, num, offset); + den += __shfl_down_sync(0xffffffff, den, offset); + } + + if (lane == 0 && den > 1e-10f && num > 0.0f) { + float depth = num / den; + if (depth < 0.5f) { + float score = num * depth; + if (score > w_best_score) { + w_best_score = score; + w_best_t0 = t0; + w_best_dur = q * period; + w_best_depth = depth; + } + } + } + } + + /* combine warp winners via shared memory (few warps; lane 0 only) */ + if (lane == 0) { + warp_best[4 * warp_id + 0] = w_best_score; + warp_best[4 * warp_id + 1] = w_best_t0; + warp_best[4 * warp_id + 2] = w_best_dur; + warp_best[4 * warp_id + 3] = w_best_depth; + } + __syncthreads(); + + if (threadIdx.x == 0) { + float b_score = -1.0f, b_t0 = 0.0f, b_dur = 0.0f, b_dep = 0.0f; + for (int w = 0; w < n_warps; w++) { + if (warp_best[4 * w] > b_score) { + b_score = warp_best[4 * w]; + b_t0 = warp_best[4 * w + 1]; + b_dur = warp_best[4 * w + 2]; + b_dep = warp_best[4 * w + 3]; + } + } + if (b_score > 0.0f) { + refined_score_out[slot] = b_score; + refined_t0_out[slot] = b_t0; + refined_duration_out[slot] = b_dur; + refined_depth_out[slot] = b_dep; + } else { + refined_score_out[slot] = -1.0f; + refined_t0_out[slot] = 0.0f; + refined_duration_out[slot] = 0.0f; + refined_depth_out[slot] = 0.0f; + } + } +} diff --git a/cuvarbase/tests/test_tls_basic.py b/cuvarbase/tests/test_tls_basic.py index 24ebdc1..52d581a 100644 --- a/cuvarbase/tests/test_tls_basic.py +++ b/cuvarbase/tests/test_tls_basic.py @@ -465,8 +465,9 @@ def test_sde_positive_with_transit(self): class TestSharedMemoryGuard: - """tls_search_gpu must fail loudly (before touching the GPU) when - the shared-memory layout exceeds the 48 KB per-block budget.""" + """The LEGACY kernel (use_fast=False) must fail loudly (before + touching the GPU) when its shared-memory layout exceeds the 48 KB + per-block budget. The default fast path has no such cap.""" def test_large_ndata_raises_value_error(self): from cuvarbase.tls import tls_search_gpu @@ -476,7 +477,8 @@ def test_large_ndata_raises_value_error(self): y = 1 + 0.001 * rand.randn(ndata) dy = 0.001 * np.ones(ndata) with pytest.raises(ValueError, match="shared memory"): - tls_search_gpu(t, y, dy, periods=np.array([1.0, 2.0])) + tls_search_gpu(t, y, dy, periods=np.array([1.0, 2.0]), + use_fast=False) def test_guard_accounts_for_template_size(self): from cuvarbase.tls import tls_search_gpu @@ -489,7 +491,20 @@ def test_guard_accounts_for_template_size(self): dy = 0.001 * np.ones(ndata) with pytest.raises(ValueError, match="shared memory"): tls_search_gpu(t, y, dy, periods=np.array([1.0, 2.0]), - n_template=4000) + n_template=4000, use_fast=False) + + def test_fast_path_has_no_ndata_cap(self): + # regression for the removed cap: the default (fast) path must + # accept TESS-length lightcurves outright + from cuvarbase.tls import tls_search_gpu + rand = np.random.RandomState(3) + ndata = 20000 + t = np.sort(27 * rand.rand(ndata)) + y = 1 + 0.001 * rand.randn(ndata) + dy = 0.001 * np.ones(ndata) + results = tls_search_gpu(t, y, dy, + periods=np.linspace(2.0, 5.0, 50)) + assert np.isfinite(results['chi2_min']) class TestFailedPeriodMasking: @@ -651,8 +666,12 @@ def test_stream_matches_default(self): dy = np.ones(400) * 0.001 periods = np.linspace(5, 15, 10) + # use_fast=False on both sides: this is a regression test for + # the LEGACY kernel's async D2H sequencing (the fast path does + # not take a user stream and would silently fall back to the + # legacy kernel anyway when one is passed) r_default = tls.tls_search_gpu(t, y, dy, periods=periods, - block_size=64) + block_size=64, use_fast=False) ensure_context() r_stream = tls.tls_search_gpu(t, y, dy, periods=periods, block_size=64, diff --git a/cuvarbase/tests/test_tls_fast.py b/cuvarbase/tests/test_tls_fast.py new file mode 100644 index 0000000..62c6090 --- /dev/null +++ b/cuvarbase/tests/test_tls_fast.py @@ -0,0 +1,223 @@ +"""GPU tests for the fast (batched, phase-binned) TLS path. + +The fast path is the default for tls_search_gpu/tls_transit; these +tests cover what the legacy-oriented suites do not: batch consistency, +the coarse/refined statistics separation, adaptive binning, chunking, +and the removal of the legacy ndata cap. +""" +import numpy as np +import pytest + +try: + import pycuda.driver # noqa: F401 + PYCUDA_AVAILABLE = True +except Exception: + PYCUDA_AVAILABLE = False + +pytestmark = pytest.mark.skipif(not PYCUDA_AVAILABLE, + reason="pycuda unavailable") + + +def make_transit_lc(period, q, depth, ndata=1500, baseline=27.0, + noise=2e-3, seed=42, t0_frac=0.3): + rng = np.random.RandomState(seed) + t = np.sort(rng.uniform(0, baseline, ndata)) + y = 1.0 + rng.randn(ndata) * noise + t0 = t0_frac * period + rel = np.abs(((t - t0 + 0.5 * period) % period) - 0.5 * period) + y[rel < 0.5 * q * period] -= depth + dy = np.full(ndata, noise) + return t, y, dy + + +def shared_grid(baseline=27.0, period_min=1.0, period_max=12.0): + from cuvarbase import tls_grids + t_ref = np.linspace(0, baseline, 500) + return tls_grids.period_grid_ofir( + t_ref, R_star=1.0, M_star=1.0, oversampling_factor=3, + period_min=period_min, period_max=period_max) + + +class TestBatchConsistency: + def test_batch_matches_single(self): + from cuvarbase import tls + periods = shared_grid() + lcs = [make_transit_lc(3.3, 0.03, 0.012, seed=1), + make_transit_lc(7.7, 0.02, 0.012, ndata=2500, seed=2)] + batch = tls.tls_search_batch(lcs, periods=periods) + singles = [tls.tls_search_batch([lc], periods=periods)[0] + for lc in lcs] + for b, s in zip(batch, singles): + # atomics make near-tied neighbors non-deterministic; + # a few grid steps of slack + assert abs(b['period'] - s['period']) / s['period'] < 5e-3 + assert abs(b['SDE'] - s['SDE']) < 1.0 + + def test_recovers_injected_periods(self): + from cuvarbase import tls + periods = shared_grid() + p_injs = [3.3, 7.7] + lcs = [make_transit_lc(p, 0.03, 0.012, seed=10 + i) + for i, p in enumerate(p_injs)] + results = tls.tls_search_batch(lcs, periods=periods) + for r, p in zip(results, p_injs): + assert abs(r['period'] - p) / p < 0.01 + assert r['SDE'] > 5 + + def test_noise_lc_scores_below_signal(self): + from cuvarbase import tls + periods = shared_grid() + rng = np.random.RandomState(3) + t = np.sort(rng.uniform(0, 27.0, 1500)) + noise_lc = (t, 1.0 + 2e-3 * rng.randn(1500), + np.full(1500, 2e-3)) + sig_lc = make_transit_lc(3.3, 0.03, 0.012, seed=4) + r_noise, r_sig = tls.tls_search_batch([noise_lc, sig_lc], + periods=periods) + assert r_noise['SDE'] < r_sig['SDE'] + + +class TestStatisticsSeparation: + def test_spectrum_is_coarse_and_uniform(self): + """Refinement must not touch the per-period spectrum: SDE + computed with refine on and off must agree.""" + from cuvarbase import tls + periods = shared_grid() + lc = make_transit_lc(3.3, 0.03, 0.012, seed=5) + r_ref = tls.tls_search_batch([lc], periods=periods, + refine_top_k=200, + return_arrays=True)[0] + r_none = tls.tls_search_batch([lc], periods=periods, + refine_top_k=0, + return_arrays=True)[0] + ok = (np.isfinite(r_ref['chi2']) & np.isfinite(r_none['chi2'])) + np.testing.assert_allclose(r_ref['chi2'][ok], + r_none['chi2'][ok], rtol=1e-2) + assert abs(r_ref['SDE'] - r_none['SDE']) < 0.5 + + def test_refined_chi2_min_not_above_coarse(self): + """The exact refinement searches a finer local grid around the + coarse optimum, so the reported chi2_min should be at or below + the coarse spectrum minimum (up to float noise).""" + from cuvarbase import tls + periods = shared_grid() + lc = make_transit_lc(3.3, 0.03, 0.012, seed=6) + r = tls.tls_search_batch([lc], periods=periods, + return_arrays=True)[0] + coarse_min = np.nanmin(r['chi2']) + assert r['chi2_min'] <= coarse_min * (1 + 1e-3) + + +class TestScalability: + def test_ndata_beyond_legacy_cap(self): + from cuvarbase import tls + periods = shared_grid() + lc = make_transit_lc(4.56, 0.025, 0.008, ndata=20000, seed=7) + r = tls.tls_search_batch([lc], periods=periods)[0] + assert abs(r['period'] - 4.56) / 4.56 < 0.01 + + def test_bjd_scale_times(self): + from cuvarbase import tls + periods = shared_grid() + t, y, dy = make_transit_lc(4.56, 0.025, 0.008, ndata=5000, + seed=8) + r = tls.tls_search_batch([(t + 2457000.0, y, dy)], + periods=periods)[0] + assert abs(r['period'] - 4.56) / 4.56 < 0.01 + # T0 reported near the (shifted) epoch + assert r['T0'] >= 2457000.0 + assert r['T0'] <= 2457000.0 + 27.0 + r['period'] + + def test_chunking_many_small_lcs(self): + """Force multiple chunks via the LC-count ceiling and check + every LC still gets a result.""" + from cuvarbase import tls + periods = shared_grid() + old = tls._TLS_FAST_MAX_OUT_FLOATS + tls._TLS_FAST_MAX_OUT_FLOATS = 3 * len(periods) # 3 LCs/chunk + try: + lcs = [make_transit_lc(3.3, 0.03, 0.012, ndata=400, + seed=20 + i) for i in range(8)] + results = tls.tls_search_batch(lcs, periods=periods) + finally: + tls._TLS_FAST_MAX_OUT_FLOATS = old + assert len(results) == 8 + for r in results: + assert 'error' not in r + assert abs(r['period'] - 3.3) / 3.3 < 0.02 + + def test_mixed_lengths_offsets(self): + from cuvarbase import tls + periods = shared_grid() + lcs = [make_transit_lc(3.3, 0.03, 0.015, ndata=n, seed=30 + i) + for i, n in enumerate((300, 4000, 1100))] + results = tls.tls_search_batch(lcs, periods=periods) + for r in results: + assert abs(r['period'] - 3.3) / 3.3 < 0.02 + + +class TestValidation: + def test_empty_batch(self): + from cuvarbase import tls + assert tls.tls_search_batch([]) == [] + + def test_mismatched_qmin_qmax(self): + from cuvarbase import tls + lc = make_transit_lc(3.3, 0.03, 0.012, ndata=300) + with pytest.raises(ValueError): + tls.tls_search_batch([lc], periods=np.linspace(2, 5, 50), + qmin=np.full(10, 0.01), + qmax=np.full(10, 0.05)) + + def test_qmin_only_rejected(self): + from cuvarbase import tls + lc = make_transit_lc(3.3, 0.03, 0.012, ndata=300) + with pytest.raises(ValueError, match="both qmin and qmax"): + tls.tls_search_batch([lc], periods=np.linspace(2, 5, 50), + qmin=np.full(50, 0.01)) + + def test_bad_n_durations(self): + from cuvarbase import tls + lc = make_transit_lc(3.3, 0.03, 0.012, ndata=300) + with pytest.raises(ValueError, match="n_durations"): + tls.tls_search_batch([lc], n_durations=100) + + +class TestRefinementFallback: + """PR #68 review regression: the coarse-parameter fallback in _finish_lc + must not depend on return_arrays being set.""" + + def test_all_refinements_fail_falls_back_no_crash(self, monkeypatch): + # Force every top-K exact refinement to return the failure sentinel + # (rscore <= 0) while the coarse phase-binned scan still finds valid + # periods. With the default batch args (refine_top_k > 0 and + # return_arrays=False) the else-branch in _finish_lc must fall back to + # the coarse best-fit t0/duration/depth — it must NOT raise + # UnboundLocalError because those coarse arrays were fetched only under + # `return_arrays or not K`. + from cuvarbase import tls + orig = tls._get_cached_fast_kernels + + def patched(*a, **k): + kern = dict(orig(*a, **k)) # copy cached {'search','refine'} + + def fail_refine(*args, **kwargs): # rscore_g is positional arg 16 + args[16].fill(np.float32(-1.0)) + + kern['refine'] = fail_refine + return kern + + monkeypatch.setattr(tls, '_get_cached_fast_kernels', patched) + periods = shared_grid() + lcs = [make_transit_lc(3.3, 0.03, 0.012, seed=1), + make_transit_lc(7.7, 0.02, 0.012, seed=2)] + res = tls.tls_search_batch(lcs, periods=periods) # defaults + assert len(res) == 2 + for r in res: + assert 'error' not in r + assert np.isfinite(r['period']) and r['period'] > 0 + assert np.isfinite(r['duration']) and np.isfinite(r['depth']) + + +if __name__ == '__main__': + pytest.main([__file__, '-v']) diff --git a/cuvarbase/tls.py b/cuvarbase/tls.py index e50dce6..4e1b29d 100644 --- a/cuvarbase/tls.py +++ b/cuvarbase/tls.py @@ -10,18 +10,19 @@ .. [2] Kovács et al. (2002), "Box Least Squares", A&A 391, 369 """ +import os import sys import threading import warnings from collections import OrderedDict +from concurrent.futures import ThreadPoolExecutor warnings.warn( "cuvarbase.tls is EXPERIMENTAL and not recommended for science use " - "in this release. The epoch (t0) grid is now duration-scaled and " - "failed periods are masked from the statistics, but the rework has " - "not yet been validated against the reference transitleastsquares " - "package. Light curves with more than ~3,500 points exceed the " - "kernel's shared-memory budget (a ValueError is raised). See " + "in this release. The default fast path (use_fast=True) is a " + "phase-binned scan with exact top-K refinement and supports " + "arbitrary ndata; the legacy kernel (use_fast=False) caps light " + "curves at ~3,500 points (a ValueError is raised). See " "analysis/V1_AUDIT_AND_GAMEPLAN.md in the repository. For validated " "transit searches use cuvarbase.bls (eebls_transit).", UserWarning) @@ -438,6 +439,8 @@ def tls_search_gpu(t, y, dy, periods=None, durations=None, block_size=None, t0_oversample=3.0, kernel=None, memory=None, stream=None, transfer_to_device=True, transfer_to_host=True, + use_fast=True, refine_top_k=50, + refine_oversample=33.0, nbins=None, **kwargs): """ Run Transit Least Squares search on GPU. @@ -533,22 +536,103 @@ def tls_search_gpu(t, y, dy, periods=None, durations=None, n_transits_min=n_transits_min ) + # The fast path keeps t in float64 for epoch subtraction; only the + # legacy path (below) downcasts inputs to float32 up front. + periods = np.asarray(periods, dtype=np.float32) + nperiods = len(periods) + + # Determine if using Keplerian mode + use_keplerian = (qmin is not None and qmax is not None) + + # Fast path: phase-binned batch engine with exact top-K refinement. + # Falls through to the legacy per-point kernel when the caller uses + # the low-level plumbing (pre-compiled kernel, external memory or + # stream, or transfer control), which the batch engine does not + # expose. + fast_gate = (kernel is None and memory is None and stream is None + and transfer_to_device and transfer_to_host) + if use_fast and not fast_gate: + warnings.warn( + "use_fast=True is ignored because a pre-compiled kernel, " + "external memory/stream, or transfer control was supplied; " + "falling back to the legacy per-point kernel (which caps " + "ndata at ~3,500 points)") + if use_fast and fast_gate: + if use_keplerian: + qmin_arr = np.asarray(qmin, dtype=np.float64) + qmax_arr = np.asarray(qmax, dtype=np.float64) + if len(qmin_arr) != nperiods or len(qmax_arr) != nperiods: + raise ValueError( + "qmin and qmax must have same length as periods " + "(%d)" % nperiods) + n_durations_eff = n_durations + else: + # match the legacy standard kernel exactly: fixed duration + # range AND its hard-coded 15 durations (the legacy kernel + # ignores n_durations outside Keplerian mode) + qmin_arr = np.full(nperiods, 0.005) + qmax_arr = np.full(nperiods, 0.15) + if n_durations != 15: + warnings.warn( + "n_durations is only honored in Keplerian mode " + "(qmin/qmax provided); the standard TLS duration " + "grid is fixed at 15 log-spaced durations") + n_durations_eff = 15 + + batch_results = tls_search_batch( + [(t, y, dy)], + periods=periods, qmin=qmin_arr, qmax=qmax_arr, + n_durations=n_durations_eff, t0_oversample=t0_oversample, + refine_top_k=refine_top_k, + refine_oversample=refine_oversample, + block_size=block_size, nbins=nbins, + limb_dark=limb_dark, u=u, + R_star=R_star, M_star=M_star, + return_arrays=True, + _warn_failed=True) + r = batch_results[0] + if 'error' in r: + raise RuntimeError(r['error']) + + # legacy result dict ('T0' is the transit phase, as before) + return { + 'periods': periods, + 'chi2': r['chi2'], + 'best_t0_per_period': r['best_t0_per_period'], + 'best_duration_per_period': r['best_duration_per_period'], + 'best_depth_per_period': r['best_depth_per_period'], + 'valid_periods': r['valid_periods'], + 'n_failed_periods': r['n_failed_periods'], + 'period': r['period'], + 'period_uncertainty': r['period_uncertainty'], + 'T0': r['t0_phase'], + 'duration': r['duration'], + 'depth': r['depth'], + 'chi2_min': r['chi2_min'], + 'SDE': r['SDE'], + 'SDE_raw': r['SDE_raw'], + 'SNR': r['SNR'], + 'FAP': r['FAP'], + 'power': r['power'], + 'SR': r['SR'], + 'n_transits': r['n_transits'], + 'R_star': R_star, + 'M_star': M_star, + } + + # ---- Legacy per-point kernel path ---- + # Convert to numpy arrays t = np.asarray(t, dtype=np.float32) y = np.asarray(y, dtype=np.float32) dy = np.asarray(dy, dtype=np.float32) - periods = np.asarray(periods, dtype=np.float32) ndata = len(t) - nperiods = len(periods) # Choose block size if block_size is None: block_size = _choose_block_size(ndata) - # Determine if using Keplerian mode - use_keplerian = (qmin is not None and qmax is not None) - # Shared-memory budget check BEFORE compiling kernels or touching # the GPU. Layout: phases[ndata] + y_sorted[ndata] + # dy_sorted[ndata] + template[n_template] + 4 thread arrays of @@ -865,3 +949,674 @@ def tls_transit(t, y, dy, R_star=1.0, M_star=1.0, R_planet=1.0, ) return results + + +# ===================================================================== +# Fast batch TLS engine (phase-binned scan + exact top-K refinement) +# ===================================================================== +# +# One kernel launch searches a whole batch of lightcurves over a shared +# period grid: grid = (nperiods, n_lightcurves), one block per +# (lightcurve, period). Each block folds its lightcurve once into +# shared-memory phase bins and scans every (duration, t0) trial against +# the bins, so trial cost is independent of ndata and there is no +# shared-memory cap on the lightcurve length. A second, exact kernel +# then re-fits the best `refine_top_k` candidate periods per lightcurve +# with per-point template evaluation on a finer local (duration, t0) +# grid. See kernels/tls_fast.cu for the algorithm notes. + +_TLS_FAST_NTEMPLATE = 1024 +_TLS_FAST_MAX_DURATIONS = 64 +_TLS_FAST_MAX_NBINS = 8192 +_TLS_FAST_DEFAULT_BLOCK = 256 + +# Chunking budgets (per kernel launch) +_TLS_FAST_MAX_OUT_FLOATS = 32 * 1024 * 1024 # per output array +_TLS_FAST_MAX_POINTS = 16 * 1024 * 1024 # concatenated data points +_TLS_FAST_MAX_GRID_Y = 65535 + + +def _next_pow2(n): + p = 1 + while p < n: + p *= 2 + return p + + +def _device_max_shared(): + """Max opt-in dynamic shared memory per block on the current device.""" + ensure_context() + dev = cuda.Context.get_device() + try: + return dev.get_attribute( + cuda.device_attribute.MAX_SHARED_MEMORY_PER_BLOCK_OPTIN) + except Exception: + return dev.get_attribute( + cuda.device_attribute.MAX_SHARED_MEMORY_PER_BLOCK) + + +def _tls_fast_shared_size(block_size, nbins): + """Dynamic shared memory (bytes) for tls_fast_search_kernel.""" + nt = _TLS_FAST_NTEMPLATE + md = _TLS_FAST_MAX_DURATIONS + n_floats = 2 * nbins + 2 * (nt + 1) + 4 * block_size + md + n_ints = md + 1 + return 4 * (n_floats + n_ints) + + +def _tls_refine_shared_size(block_size): + """Dynamic shared memory (bytes) for tls_refine_kernel.""" + return 4 * ((_TLS_FAST_NTEMPLATE + 1) + 4 * (block_size // 32)) + + +def _auto_nbins(qmin_global, t0_oversample, block_size): + """Pick the phase-bin count: bin width <= qmin/t0_oversample, power + of two, bounded by the device's shared-memory limit.""" + need = t0_oversample / max(float(qmin_global), 1e-6) + nbins = _next_pow2(int(np.ceil(need))) + nbins = max(256, min(nbins, _TLS_FAST_MAX_NBINS)) + max_shared = _device_max_shared() + while nbins > 256 and _tls_fast_shared_size(block_size, nbins) > max_shared: + nbins //= 2 + if nbins < need: + warnings.warn( + "TLS fast path: %d phase bins under-resolve the narrowest " + "trial duration (q=%.2e wants %d bins); the coarse scan is " + "smeared there and recovery relies on the exact refinement " + "pass (refine_top_k)." % (nbins, qmin_global, + int(np.ceil(need)))) + return nbins + + +def compile_tls_fast(block_size=_TLS_FAST_DEFAULT_BLOCK, nbins=2048, + t0_oversample=3.0, refine_nd=3): + """ + Compile the fast (batched, phase-binned) TLS kernels. + + Parameters + ---------- + block_size : int + CUDA block size (multiple of 32). + nbins : int + Number of phase bins (power of two). + t0_oversample : float + Epoch oversampling: t0 stride = duration / t0_oversample in the + coarse scan (same convention as the legacy kernels). + refine_nd : int + Number of local durations in the refinement kernel (odd; + default 3 spans one coarse duration-grid step each way). + + Returns + ------- + kernels : dict + {'search': ..., 'refine': ...} PyCUDA functions. + """ + ensure_context() + if block_size < 32 or (block_size & (block_size - 1)): + # the block max-reduction assumes a power-of-two blockDim + raise ValueError("block_size must be a power of two >= 32") + if nbins & (nbins - 1): + raise ValueError("nbins must be a power of two") + if int(refine_nd) != refine_nd or refine_nd < 2: + raise ValueError("refine_nd must be an integer >= 2 " + "(odd recommended so the coarse duration sits " + "on the refinement grid)") + + cppd = dict(BLOCK_SIZE=block_size, + NBINS=nbins, + NTEMPLATE=_TLS_FAST_NTEMPLATE, + MAX_DURATIONS=_TLS_FAST_MAX_DURATIONS, + T0_OVERSAMPLE=float(t0_oversample), + REFINE_ND=refine_nd) + kernel_txt = _module_reader(find_kernel('tls_fast'), cpp_defs=cppd) + module = SourceModule(kernel_txt, options=['--use_fast_math'], + no_extern_c=True) + search = module.get_function('tls_fast_search_kernel') + refine = module.get_function('tls_refine_kernel') + + smem = _tls_fast_shared_size(block_size, nbins) + if smem > _SHARED_MEM_LIMIT: + max_shared = _device_max_shared() + if smem > max_shared: + raise ValueError( + "TLS fast kernel wants %d bytes of shared memory per " + "block but the device caps at %d; reduce nbins (or " + "block_size)" % (smem, max_shared)) + # opt in to >48KB dynamic shared memory (sm_70+) + search.set_attribute( + cuda.function_attribute.MAX_DYNAMIC_SHARED_SIZE_BYTES, smem) + + return {'search': search, 'refine': refine} + + +def _get_cached_fast_kernels(block_size, nbins, t0_oversample, + refine_nd=3): + key = ('fast', block_size, nbins, float(t0_oversample), refine_nd) + with _kernel_cache_lock: + if key in _kernel_cache: + _kernel_cache.move_to_end(key) + return _kernel_cache[key] + compiled = compile_tls_fast(block_size=block_size, nbins=nbins, + t0_oversample=t0_oversample, + refine_nd=refine_nd) + _kernel_cache[key] = compiled + _kernel_cache.move_to_end(key) + if len(_kernel_cache) > _KERNEL_CACHE_MAX_SIZE: + _kernel_cache.popitem(last=False) + return compiled + + +def _preprocess_batch(lightcurves): + """Epoch-subtract, weight, and concatenate lightcurves (float64 + accumulation; times stored as a float-float hi/lo pair so the + kernels can fold at ~float64 precision with pure FP32 math). + + Returns (t_hi, t_lo, a_c, b_c, offs, lens, chi2_0, epochs, spans); + chi2_0 stays float64 for cancellation-free chi2 reconstruction. + """ + n_lc = len(lightcurves) + lens = np.array([len(lc[0]) for lc in lightcurves], dtype=np.int64) + for i, (lc, n) in enumerate(zip(lightcurves, lens)): + if n == 0: + raise ValueError("lightcurve %d is empty" % i) + if len(lc[1]) != n or len(lc[2]) != n: + raise ValueError( + "lightcurve %d: t, y, dy lengths differ (%d, %d, %d)" + % (i, n, len(lc[1]), len(lc[2]))) + # batch-wide offsets in int64 (a large survey can exceed 2^31 + # total points); per-chunk offsets are rebased and cast to int32 + # at upload, where the chunk-size cap keeps them small + offs = np.zeros(n_lc, dtype=np.int64) + if n_lc > 1: + offs[1:] = np.cumsum(lens)[:-1] + total = int(lens.sum()) + + t_hi = np.empty(total, dtype=np.float32) + t_lo = np.empty(total, dtype=np.float32) + a_c = np.empty(total, dtype=np.float32) + b_c = np.empty(total, dtype=np.float32) + chi2_0 = np.empty(n_lc, dtype=np.float64) + epochs = np.empty(n_lc, dtype=np.float64) + spans = np.empty(n_lc, dtype=np.float64) + + for i, (t, y, dy) in enumerate(lightcurves): + t64 = np.asarray(t, dtype=np.float64) + y64 = np.asarray(y, dtype=np.float64) + dy64 = np.asarray(dy, dtype=np.float64) + epoch = np.floor(t64.min()) + # sigma^2 regularizer matches the legacy kernel (float32 dy) + s2 = dy64 * dy64 + 1e-10 + o, n = int(offs[i]), int(lens[i]) + tshift = t64 - epoch + hi = tshift.astype(np.float32) + t_hi[o:o + n] = hi + t_lo[o:o + n] = (tshift - hi.astype(np.float64)).astype(np.float32) + resid = 1.0 - y64 + a_c[o:o + n] = resid / s2 + b_c[o:o + n] = 1.0 / s2 + chi2_0[i] = np.sum(resid * resid / s2) + epochs[i] = epoch + spans[i] = t64.max() - t64.min() + + return t_hi, t_lo, a_c, b_c, offs, lens, chi2_0, epochs, spans + + +def tls_search_batch(lightcurves, R_star=1.0, M_star=1.0, R_planet=1.0, + periods=None, qmin=None, qmax=None, + period_min=None, period_max=None, + n_transits_min=2, oversampling_factor=3, + qmin_fac=0.5, qmax_fac=2.0, n_durations=15, + t0_oversample=3.0, + refine_top_k=50, refine_oversample=33.0, + block_size=None, nbins=None, + limb_dark='quadratic', u=[0.4804, 0.1867], + return_arrays=False, sde_kernel_size=None, + _warn_failed=False): + """ + Survey-scale Transit Least Squares search over a batch of + lightcurves sharing one trial-period grid. + + This is the fast path for N >> 1 lightcurves: a single kernel + launch (per chunk) searches every (lightcurve, period) pair with a + phase-binned scan, then an exact per-point refinement kernel + re-fits the ``refine_top_k`` best candidate periods per lightcurve + on a finer local (duration, t0) grid. There is no cap on ndata. + + Parameters + ---------- + lightcurves : list of (t, y, dy) tuples + Times (days), fluxes (normalized to a baseline of 1.0), and + flux uncertainties. Each lightcurve's epoch floor(min(t)) is + subtracted internally (float64), so BJD-scale times are safe. + R_star, M_star : float + Stellar radius/mass in solar units; set the period grid and the + Keplerian duration window (shared by all lightcurves). + R_planet : float + Fiducial planet radius (Earth radii) for the duration window. + periods, qmin, qmax : array_like, optional + Explicit trial grid: periods (days) and per-period fractional + duration bounds. Auto-generated (Ofir 2014 grid + Keplerian + durations) when omitted. + period_min, period_max : float, optional + Period search range for the auto grid. + n_transits_min, oversampling_factor : optional + Auto period-grid parameters (see tls_grids.period_grid_ofir). + qmin_fac, qmax_fac : float + Keplerian duration window factors (search [qmin_fac*q, + qmax_fac*q] at each period). + n_durations : int + Trial durations per period (log-spaced), max 64. + t0_oversample : float + Coarse epoch oversampling; t0 stride = duration / t0_oversample. + refine_top_k : int + Number of best candidate periods per lightcurve re-fit exactly + (default 50; 0 disables refinement). + refine_oversample : float + Refinement epoch stride = duration / refine_oversample (the + reference transitleastsquares package uses ~100). + block_size : int, optional + CUDA block size override (power of two). By default each + bin-count band picks its own (256, or 512 for bands with 4096+ + bins, shrunk to fit the device's shared-memory cap). + nbins : int, optional + Phase bins (power of two). Auto-sized so a bin is no wider than + the narrowest trial duration / t0_oversample, within the + device's shared-memory limit. + limb_dark, u : optional + Limb-darkening law/coefficients for the transit template. + return_arrays : bool + Also return the per-period chi2/t0/duration/depth arrays and + derived spectra for each lightcurve (adds D2H transfer time). + sde_kernel_size : int, optional + Median-detrend window for the SDE statistic (see tls_stats). + + Returns + ------- + results : list of dict + One dict per lightcurve: + 'period', 'period_uncertainty', 't0_phase', 'T0' (absolute + mid-transit time near the epoch), 'duration', 'depth', + 'chi2_min', 'SDE', 'SDE_raw', 'SNR', 'FAP', 'n_transits', + 'n_failed_periods'; plus the per-period arrays when + ``return_arrays`` is set. A lightcurve whose every trial period + failed gets {'error': message} instead. + + The best-fit parameters (including 'chi2_min') come from the + exact refinement pass, so 'chi2_min' is generally slightly + below the minimum of the returned coarse 'chi2' spectrum; the + SDE/FAP statistics are computed from the uniform coarse + spectrum only, keeping the detection statistic's scale + consistent across periods. + """ + tls_grids.validate_stellar_parameters(R_star, M_star) + tls_models.validate_limb_darkening_coeffs(u, limb_dark) + + if len(lightcurves) == 0: + return [] + if n_durations < 2 or n_durations > _TLS_FAST_MAX_DURATIONS: + raise ValueError("n_durations must be in [2, %d]" % + _TLS_FAST_MAX_DURATIONS) + if refine_top_k is not None and refine_top_k < 0: + raise ValueError("refine_top_k must be >= 0 (got %r)" + % (refine_top_k,)) + if refine_top_k and not refine_oversample > 0: + raise ValueError("refine_oversample must be > 0 (got %r)" + % (refine_oversample,)) + + # ---- Trial grid (shared across the batch) ---- + if periods is None: + # build the grid from the longest lightcurve baseline + spans_probe = [np.max(lc[0]) - np.min(lc[0]) for lc in lightcurves] + t_ref = lightcurves[int(np.argmax(spans_probe))][0] + periods = tls_grids.period_grid_ofir( + t_ref, R_star=R_star, M_star=M_star, + oversampling_factor=oversampling_factor, + period_min=period_min, period_max=period_max, + n_transits_min=n_transits_min) + periods = np.asarray(periods, dtype=np.float32) + nperiods = len(periods) + if nperiods == 0: + raise ValueError("periods must be non-empty") + + if (qmin is None) != (qmax is None): + raise ValueError("provide both qmin and qmax, or neither") + if qmin is None: + # only the q bounds are needed here; skip building the + # (nperiods x n_durations) duration table + q_values = tls_grids.q_transit(periods.astype(np.float64), + R_star=R_star, M_star=M_star, + R_planet=R_planet) + qmin = q_values * qmin_fac + qmax = q_values * qmax_fac + qmin = np.ascontiguousarray(qmin, dtype=np.float32) + qmax = np.ascontiguousarray(qmax, dtype=np.float32) + if len(qmin) != nperiods or len(qmax) != nperiods: + raise ValueError("qmin and qmax must have same length as periods " + "(%d)" % nperiods) + if np.any(qmin <= 0) or np.any(qmax < qmin) or np.any(qmax >= 1): + raise ValueError( + "need 0 < qmin <= qmax < 1 at every period (the transit " + "duration must be shorter than the period; the binned scan " + "would double-count phase bins for q >= 1)") + + # ---- Kernel configuration: band the grid by required bin count. + # The trial-scan cost is proportional to NBINS, while the bin count + # a period actually needs scales with 1/qmin at that period, so + # running the whole grid at the finest band's NBINS overpays by 2x+ + # on long-baseline searches. Each band compiles (and caches) its + # own NBINS variant and scatters results through period_map. ---- + qmin_global = float(np.min(qmin)) + max_dev_shared = _device_max_shared() + ensure_context() + cc_major = cuda.Context.get_device().compute_capability()[0] + + def _band_block_size(nb): + if block_size is not None: + return block_size + # Swept on RTX A5000 (sm_86), RTX 4000 Ada (sm_89) and Tesla + # V100 (sm_70), kepler-4yr config with the float-float fold: + # 256 beats 128 everywhere; 512 wins on the big-bin bands on + # Ampere/Ada from 4096 bins up, while Volta prefers 256 until + # shared memory forces one block per SM (8192 bins). + # On devices with a hard 48KB cap (no opt-in; Pascal and + # earlier) prefer shrinking the block over losing phase bins. + big_bin_threshold = 4096 if cc_major >= 8 else 8192 + bs = 512 if nb >= big_bin_threshold else 256 + while bs > 64 and _tls_fast_shared_size(bs, nb) > max_dev_shared: + bs //= 2 + return bs + + need = t0_oversample / np.maximum(qmin.astype(np.float64), 1e-6) + if nbins is None: + nbins_per = np.power( + 2, np.ceil(np.log2(np.clip(need, 256, None)))).astype(np.int64) + nbins_per = np.minimum(nbins_per, _TLS_FAST_MAX_NBINS) + # shared-memory cap for this device + while _tls_fast_shared_size( + _band_block_size(int(nbins_per.max())), + int(nbins_per.max())) > max_dev_shared: + cap = int(nbins_per.max()) // 2 + nbins_per = np.minimum(nbins_per, cap) + if cap <= 256: + break + short = need > nbins_per + if np.any(short): + warnings.warn( + "TLS fast path: %d of %d trial periods have their " + "narrowest durations under-resolved by the phase bins " + "(device shared-memory cap); their coarse scan is " + "smeared and recovery there relies on the exact " + "refinement pass." % (int(short.sum()), nperiods)) + bands = [(int(nb), np.flatnonzero(nbins_per == nb).astype(np.int32)) + for nb in np.unique(nbins_per)] + smear = float(np.max(need / nbins_per)) + else: + bands = [(int(nbins), np.arange(nperiods, dtype=np.int32))] + smear = float(np.max(need / nbins)) + + # When the coarse bins under-resolve a duration (smear > 1), the + # coarse best duration is biased wide by the bin convolution; + # widen the refinement's duration window accordingly and use more + # local durations so the true value stays inside it. + smear = max(1.0, smear) + refine_nd = 3 if smear <= 1.3 else 5 + + band_launches = [] # (kernels, block_size, smem, n, per_g, qmn_g, qmx_g, map_g) + for nb, idx in bands: + bs = _band_block_size(nb) + kern = _get_cached_fast_kernels(bs, nb, t0_oversample, + refine_nd=refine_nd) + band_launches.append(( + kern, bs, _tls_fast_shared_size(bs, nb), len(idx), + gpuarray.to_gpu(periods[idx]), + gpuarray.to_gpu(qmin[idx]), + gpuarray.to_gpu(qmax[idx]), + gpuarray.to_gpu(idx))) + + # refinement runs at the first band's block size (any variant works) + refine_bs = _band_block_size(bands[0][0]) + refine_kern = band_launches[0][0] + refine_smem = _tls_refine_shared_size(refine_bs) + + # refinement trial-grid shape (see kernels/tls_fast.cu). The t0 + # halfwidth must cover the worst coarse quantization, which lives + # in the FINEST band if the device cap clamped it below its need. + dur_ratio = float(np.median(qmax / qmin)) + dur_span = dur_ratio ** (1.0 / (2.0 * max(n_durations - 1, 1))) + dur_span *= min(smear, 4.0) + nbins_finest = bands[-1][0] + t0_halfwidth = min(3.0, max(0.5, 1.5 / (nbins_finest * qmin_global))) + + # ---- Template tables ---- + T_tab, S1_tab, S2_tab = tls_models.generate_template_tables( + n_table=_TLS_FAST_NTEMPLATE, limb_dark=limb_dark, u=u) + + # ---- Host preprocessing ---- + t_hi_c, t_lo_c, a_c, b_c, offs, lens, chi2_0, epochs, spans = \ + _preprocess_batch(lightcurves) + n_lc = len(lightcurves) + + # ---- Static GPU arrays ---- + periods_g = gpuarray.to_gpu(periods) + T_g = gpuarray.to_gpu(T_tab) + S1_g = gpuarray.to_gpu(S1_tab) + S2_g = gpuarray.to_gpu(S2_tab) + + # ---- Chunk plan: bound output size, data size, and grid.y ---- + max_lcs_by_out = max(1, _TLS_FAST_MAX_OUT_FLOATS // max(nperiods, 1)) + chunks = [] # list of (i0, i1) + i0 = 0 + while i0 < n_lc: + i1 = i0 + 1 + pts = int(lens[i0]) + while (i1 < n_lc + and i1 - i0 < max_lcs_by_out + and i1 - i0 < _TLS_FAST_MAX_GRID_Y + and pts + int(lens[i1]) <= _TLS_FAST_MAX_POINTS): + pts += int(lens[i1]) + i1 += 1 + chunks.append((i0, i1)) + i0 = i1 + + max_chunk_lcs = max(i1 - i0 for i0, i1 in chunks) + max_chunk_pts = max(int(lens[i0:i1].sum()) for i0, i1 in chunks) + + # reusable per-chunk GPU buffers + thi_g = gpuarray.empty(max_chunk_pts, np.float32) + tlo_g = gpuarray.empty(max_chunk_pts, np.float32) + a_g = gpuarray.empty(max_chunk_pts, np.float32) + b_g = gpuarray.empty(max_chunk_pts, np.float32) + off_g = gpuarray.empty(max_chunk_lcs, np.int32) + len_g = gpuarray.empty(max_chunk_lcs, np.int32) + out_n = max_chunk_lcs * nperiods + score_g = gpuarray.empty(out_n, np.float32) + t0_g = gpuarray.empty(out_n, np.float32) + dur_g = gpuarray.empty(out_n, np.float32) + depth_g = gpuarray.empty(out_n, np.float32) + + # Refinement targets the peak region only: capping K at ~10% of the + # grid keeps the SDE background dominated by uniformly-treated + # (coarse) periods, so the refined peak stands out the same way it + # would in a full-fidelity spectrum. + K = int(min(refine_top_k, max(16, nperiods // 10), + nperiods)) if refine_top_k else 0 + if K: + cand_g = gpuarray.empty(max_chunk_lcs * K, np.int32) + # compact refined outputs, one slot per candidate; the coarse + # spectrum is never overwritten (SDE needs uniform fidelity) + rscore_g = gpuarray.empty(max_chunk_lcs * K, np.float32) + rt0_g = gpuarray.empty(max_chunk_lcs * K, np.float32) + rdur_g = gpuarray.empty(max_chunk_lcs * K, np.float32) + rdepth_g = gpuarray.empty(max_chunk_lcs * K, np.float32) + + results = [None] * n_lc + + for (i0, i1) in chunks: + nc = i1 - i0 + p0 = int(offs[i0]) + pts = int(lens[i0:i1].sum()) + + # H2D (chunk-relative offsets are bounded by the points cap, + # so the int32 cast is safe) + thi_g[:pts].set(t_hi_c[p0:p0 + pts]) + tlo_g[:pts].set(t_lo_c[p0:p0 + pts]) + a_g[:pts].set(a_c[p0:p0 + pts]) + b_g[:pts].set(b_c[p0:p0 + pts]) + off_g[:nc].set((offs[i0:i1] - p0).astype(np.int32)) + len_g[:nc].set(lens[i0:i1].astype(np.int32)) + + # coarse binned scan, one launch per bin-count band + for kern, bs, smem, band_n, per_g, qmn_g, qmx_g, map_g \ + in band_launches: + kern['search']( + thi_g, tlo_g, a_g, b_g, off_g, len_g, + per_g, qmn_g, qmx_g, map_g, S1_g, S2_g, + np.int32(band_n), np.int32(nperiods), + np.int32(n_durations), + score_g, t0_g, dur_g, depth_g, + block=(bs, 1, 1), grid=(band_n, nc, 1), + shared=smem) + + # score = chi2_0 - chi2 (cancellation-free); <= 0 marks failure + score_h = score_g[:nc * nperiods].get().reshape(nc, nperiods) + + # exact refinement of the best K candidate periods per LC + # (parameters only; the coarse spectrum feeds the statistics) + rscore_h = rt0_h = rdur_h = rdepth_h = cand = None + if K: + cand = np.empty((nc, K), dtype=np.int32) + for j in range(nc): + if K < nperiods: + # K largest scores = K smallest chi2; failed + # periods (score < 0) sort last automatically + cand[j] = np.argpartition(-score_h[j], K)[:K] + else: + cand[j] = np.arange(nperiods) + cand_g[:nc * K].set(cand.ravel()) + refine_kern['refine']( + thi_g, tlo_g, a_g, b_g, off_g, len_g, + periods_g, cand_g, T_g, + np.int32(nperiods), np.int32(K), + np.float32(dur_span), np.float32(t0_halfwidth), + np.float32(refine_oversample), + t0_g, dur_g, + rscore_g, rt0_g, rdur_g, rdepth_g, + block=(refine_bs, 1, 1), grid=(K, nc, 1), + shared=refine_smem) + rscore_h = rscore_g[:nc * K].get().reshape(nc, K) + rt0_h = rt0_g[:nc * K].get().reshape(nc, K) + rdur_h = rdur_g[:nc * K].get().reshape(nc, K) + rdepth_h = rdepth_g[:nc * K].get().reshape(nc, K) + + # Coarse per-period best-fit params. Needed when return_arrays is set, + # when there is no refinement (K == 0), AND as the fallback in + # _finish_lc when a light curve's top-K exact refinements all return + # the sentinel (the else-branch below reads t0_h/dur_h/depth_h). Fetch + # only when actually needed so the common default path pays no extra + # D2H. (`rscore_h` is only touched when K > 0, where it is bound.) + if (return_arrays or not K + or bool((rscore_h.max(axis=1) <= 0.0).any())): + t0_h = t0_g[:nc * nperiods].get().reshape(nc, nperiods) + dur_h = dur_g[:nc * nperiods].get().reshape(nc, nperiods) + depth_h = depth_g[:nc * nperiods].get().reshape(nc, nperiods) + + # ---- Per-LC statistics (pure CPU; threaded across the chunk, + # scipy/numpy release the GIL in the hot medfilt) ---- + def _finish_lc(j): + lc_idx = i0 + j + srow = score_h[j] + valid = srow > 0.0 + n_failed = int(nperiods - valid.sum()) + if n_failed == nperiods: + return lc_idx, { + 'error': "TLS kernel returned no valid solution for " + "any of the %d trial periods" % nperiods} + if n_failed and _warn_failed: + warnings.warn( + "%d of %d trial periods returned no valid TLS " + "solution (chi2 sentinel); they are excluded from " + "the best-fit search and the SDE/FAP statistics and " + "appear as NaN in the returned arrays" + % (n_failed, nperiods)) + + # chi2 reconstructed in float64 against the float64 chi2_0 + row = chi2_0[lc_idx] - srow.astype(np.float64) + chi2_valid = row[valid] + periods_valid = periods[valid] + + # Best-fit parameters come from the exact refinement pass + # when available; the coarse spectrum (row) is what feeds + # the SDE/FAP statistics either way. + slot = int(np.argmax(rscore_h[j])) if K else 0 + if K and rscore_h[j, slot] > 0.0: + best_idx = int(cand[j, slot]) + best_t0 = float(rt0_h[j, slot]) + best_duration = float(rdur_h[j, slot]) + best_depth = float(rdepth_h[j, slot]) + chi2_min = float(chi2_0[lc_idx] - rscore_h[j, slot]) + best_valid_idx = int(np.searchsorted( + np.flatnonzero(valid), best_idx)) + else: + best_valid_idx = int(np.argmin(chi2_valid)) + best_idx = int(np.flatnonzero(valid)[best_valid_idx]) + chi2_min = float(row[best_idx]) + best_t0 = float(t0_h[j, best_idx]) + best_duration = float(dur_h[j, best_idx]) + best_depth = float(depth_h[j, best_idx]) + + best_period = float(periods[best_idx]) + n_transits = int(spans[lc_idx] / best_period) + + stats = tls_stats.compute_all_statistics( + chi2_valid, periods_valid, best_valid_idx, + best_depth, best_duration, n_transits, + kernel_size=sde_kernel_size) + period_uncertainty = tls_stats.compute_period_uncertainty( + periods_valid, chi2_valid, best_valid_idx) + + res = { + 'period': best_period, + 'period_uncertainty': period_uncertainty, + 't0_phase': best_t0, + 'T0': epochs[lc_idx] + best_t0 * best_period, + 'duration': best_duration, + 'depth': best_depth, + 'chi2_min': chi2_min, + 'SDE': stats['SDE'], + 'SDE_raw': stats['SDE_raw'], + 'SNR': stats['SNR'], + 'FAP': stats['FAP'], + 'n_transits': n_transits, + 'n_failed_periods': n_failed, + } + if return_arrays: + def _expand(values): + full = np.full(nperiods, np.nan) + full[valid] = values + return full + res.update({ + 'periods': periods, + 'chi2': np.where(valid, row, np.nan), + 'best_t0_per_period': t0_h[j].copy(), + 'best_duration_per_period': dur_h[j].copy(), + 'best_depth_per_period': depth_h[j].copy(), + 'valid_periods': valid, + 'power': _expand(stats['power']), + 'SR': _expand(stats['SR']), + }) + return lc_idx, res + + if nc > 1: + n_workers = min(8, os.cpu_count() or 1, nc) + else: + n_workers = 1 + if n_workers > 1: + with ThreadPoolExecutor(max_workers=n_workers) as pool: + for lc_idx, res in pool.map(_finish_lc, range(nc)): + results[lc_idx] = res + else: + for j in range(nc): + lc_idx, res = _finish_lc(j) + results[lc_idx] = res + + return results diff --git a/cuvarbase/tls_grids.py b/cuvarbase/tls_grids.py index 4132851..5a4a7ee 100644 --- a/cuvarbase/tls_grids.py +++ b/cuvarbase/tls_grids.py @@ -339,20 +339,18 @@ def duration_grid_keplerian(periods, R_star=1.0, M_star=1.0, R_planet=1.0, qmin_vals = q_values * qmin_fac qmax_vals = q_values * qmax_fac - durations = [] duration_counts = np.full(len(periods), n_durations, dtype=np.int32) - for period, qmin, qmax in zip(periods, qmin_vals, qmax_vals): - # Logarithmically-spaced durations from qmin to qmax - # (in absolute time, not fractional) - dur_min = qmin * period - dur_max = qmax * period - - # Log-spaced grid - dur = np.logspace(np.log10(dur_min), np.log10(dur_max), - n_durations, dtype=np.float32) - - durations.append(dur) + # Logarithmically-spaced durations from qmin*P to qmax*P per period + # (absolute time, not fractional), vectorized over the whole grid: + # equivalent to np.logspace per period, but one broadcast instead of + # len(periods) Python-level calls (which dominate at ~1e5 periods). + log_min = np.log10(qmin_vals * periods) + log_max = np.log10(qmax_vals * periods) + frac = np.linspace(0.0, 1.0, n_durations) + dur_2d = 10.0 ** (log_min[:, None] + + (log_max - log_min)[:, None] * frac[None, :]) + durations = list(dur_2d.astype(np.float32)) return durations, duration_counts, q_values diff --git a/cuvarbase/tls_models.py b/cuvarbase/tls_models.py index 7a86c64..aad38d3 100644 --- a/cuvarbase/tls_models.py +++ b/cuvarbase/tls_models.py @@ -368,6 +368,62 @@ def generate_transit_template(n_template=1000, limb_dark='quadratic', return _trapezoid_template(n_template) +def generate_template_tables(n_table=1024, limb_dark='quadratic', + u=[0.4804, 0.1867], oversample=8): + """ + Generate the template lookup tables used by the fast TLS kernel. + + The fast kernel evaluates the transit template two ways: + + - The binned scan needs the template's *running integrals* so it can + compute the exact bin-averaged template over any transit-coordinate + interval (area sampling): ``S1(x) = int_{-1}^{x} T dx`` and + ``S2(x) = int_{-1}^{x} T^2 dx``. + - The refinement kernel needs the pointwise template ``T(x)`` itself. + + All three are tabulated on the same uniform grid of ``n_table + 1`` + knots spanning transit_coord in [-1, 1]. The integrals are computed + from a template oversampled by ``oversample`` relative to the knot + grid (trapezoid rule), so S1/S2 are accurate even where T is curved. + + Parameters + ---------- + n_table : int, optional + Number of table intervals; the returned arrays have + ``n_table + 1`` entries (default: 1024). + limb_dark : str, optional + Limb darkening law (default: 'quadratic') + u : list, optional + Limb darkening coefficients (default: [0.4804, 0.1867]) + oversample : int, optional + Oversampling of the integrand relative to the knot grid. + + Returns + ------- + T, S1, S2 : ndarray + Float32 arrays of shape (n_table + 1,). + """ + n_fine = n_table * oversample + fine = generate_transit_template(n_template=n_fine + 1, + limb_dark=limb_dark, u=u) + fine = np.asarray(fine, dtype=np.float64) + dx = 2.0 / n_fine + + def running_integral(values): + # cumulative trapezoid on the fine grid, then subsample to knots + cum = np.concatenate([ + [0.0], np.cumsum(0.5 * (values[1:] + values[:-1]) * dx)]) + return cum[::oversample] + + S1 = running_integral(fine) + S2 = running_integral(fine ** 2) + T = fine[::oversample] + + return (T.astype(np.float32), + S1.astype(np.float32), + S2.astype(np.float32)) + + def _trapezoid_template(n_template=1000, ingress_fraction=0.1): """ Generate a trapezoidal transit template as fallback. diff --git a/cuvarbase/tls_stats.py b/cuvarbase/tls_stats.py index 9dda6b2..3d9b61c 100644 --- a/cuvarbase/tls_stats.py +++ b/cuvarbase/tls_stats.py @@ -49,7 +49,7 @@ def signal_residue(chi2, chi2_null=None): def signal_detection_efficiency(chi2, chi2_null=None, detrend=True, - window_length=None): + kernel_size=None, window_length=None): """ Calculate Signal Detection Efficiency (SDE). @@ -64,8 +64,18 @@ def signal_detection_efficiency(chi2, chi2_null=None, detrend=True, Null hypothesis chi-squared detrend : bool, optional Apply median filter detrending (default: True) + kernel_size : int, optional + Running-median kernel size for detrending. If None (default), + uses ``min(len(SR)//10 forced odd (min 3), 91)``: small period + grids keep the length-proportional window, while large grids + are capped at 91 points -- the fixed-kernel convention of the + reference ``transitleastsquares`` package (oversampling factor + 3 x SDE_MEDIAN_KERNEL_SIZE 30, forced odd). Passing an explicit + value overrides the automatic choice (even values are rounded + up to the next odd integer, as required by the median filter). window_length : int, optional - Window length for median filter (default: len(chi2)//10) + Deprecated alias for ``kernel_size``; ignored when + ``kernel_size`` is given. Returns ------- @@ -82,6 +92,10 @@ def signal_detection_efficiency(chi2, chi2_null=None, detrend=True, SDE = (max(SR) - mean(SR)) / std(SR) Typical threshold: SDE > 7 for 1% false alarm probability + + Following ``transitleastsquares`` (Hippke & Heller 2019), detrending + is skipped entirely when ``len(SR) <= 2 * kernel_size``; in that + case the raw SDE and raw SR are returned unchanged. """ chi2 = np.asarray(chi2) @@ -99,28 +113,45 @@ def signal_detection_efficiency(chi2, chi2_null=None, detrend=True, # Detrend with median filter if requested if detrend: - if window_length is None: - window_length = max(len(SR) // 10, 3) + if kernel_size is None: + kernel_size = window_length # deprecated alias + if kernel_size is None: + kernel_size = max(len(SR) // 10, 3) # Ensure odd window - if window_length % 2 == 0: - window_length += 1 - - # Apply median filter to remove trends - SR_trend = signal.medfilt(SR, kernel_size=window_length) + if kernel_size % 2 == 0: + kernel_size += 1 + # Cap at the fixed 91-point kernel used by the reference + # transitleastsquares implementation; an uncapped len//10 + # window makes medfilt O(n*k) ~ O(n^2/10) and takes minutes + # of CPU at survey-scale period grids (n ~ 1e5). + kernel_size = min(kernel_size, 91) + elif kernel_size % 2 == 0: + # medfilt requires an odd kernel + kernel_size += 1 + + if len(SR) <= 2 * kernel_size: + # Too few points to estimate a trend; follow the reference + # transitleastsquares behavior and skip detrending. + SDE = SDE_raw + power = SR + else: + # Apply median filter to remove trends + SR_trend = signal.medfilt(SR, kernel_size=kernel_size) - # Detrended signal residue - SR_detrended = SR - SR_trend + np.median(SR) + # Detrended signal residue + SR_detrended = SR - SR_trend + np.median(SR) - # Calculate SDE on detrended signal - mean_SR_detrended = np.mean(SR_detrended) - std_SR_detrended = np.std(SR_detrended) + # Calculate SDE on detrended signal + mean_SR_detrended = np.mean(SR_detrended) + std_SR_detrended = np.std(SR_detrended) - if std_SR_detrended < 1e-10: - SDE = 0.0 - else: - SDE = (np.max(SR_detrended) - mean_SR_detrended) / std_SR_detrended + if std_SR_detrended < 1e-10: + SDE = 0.0 + else: + SDE = ((np.max(SR_detrended) - mean_SR_detrended) + / std_SR_detrended) - power = SR_detrended + power = SR_detrended else: SDE = SDE_raw power = SR @@ -279,7 +310,7 @@ def odd_even_mismatch(depths_odd, depths_even): def compute_all_statistics(chi2, periods, best_period_idx, depth, duration, n_transits, - depths_per_transit=None): + depths_per_transit=None, kernel_size=None): """ Compute all TLS statistics for a search result. @@ -299,6 +330,11 @@ def compute_all_statistics(chi2, periods, best_period_idx, Number of transits at best period depths_per_transit : array_like, optional Individual transit depths + kernel_size : int, optional + Running-median kernel for SDE detrending, passed through to + :func:`signal_detection_efficiency`. Default (None) uses + ``min(len(chi2)//10 forced odd, 91)``, following the fixed + 91-point kernel convention of ``transitleastsquares``. Returns ------- @@ -313,7 +349,8 @@ def compute_all_statistics(chi2, periods, best_period_idx, - odd_even_mismatch: Odd/even depth difference (if available) """ # Signal residue and SDE - SDE, SDE_raw, power = signal_detection_efficiency(chi2, detrend=True) + SDE, SDE_raw, power = signal_detection_efficiency( + chi2, detrend=True, kernel_size=kernel_size) SR = signal_residue(chi2) diff --git a/scripts/benchmark_tls_survey.py b/scripts/benchmark_tls_survey.py new file mode 100644 index 0000000..9f3d39f --- /dev/null +++ b/scripts/benchmark_tls_survey.py @@ -0,0 +1,480 @@ +#!/usr/bin/env python +"""Survey-scale TLS throughput benchmark (end-to-end, GPU). + +Measures wall time per lightcurve (grid generation + preprocessing + H2D + +kernel + D2H + statistics) for N lightcurves per survey regime, comparing up +to three implementations (each degrades gracefully if unavailable): + + new cuvarbase.tls.tls_search_batch (batch API) + old cuvarbase.tls.tls_transit looped per LC (ndata <= 3300 only; + capped at --old-nlc LCs, per-LC median extrapolated) + reference CPU transitleastsquares (--ref-nlc LCs; kepler-4yr skipped + unless --ref-all) + +Half the lightcurves carry an injected box transit (Keplerian duration, +Sun-like), half are pure noise; recovery + median SDE reported per half. + +Usage (RunPod pod): + ./scripts/run-remote.sh python scripts/benchmark_tls_survey.py \\ + [--regimes tess-ffi,k2] [--impls new,old,reference] [--quick] + +Output: JSON via --output plus a human-readable summary table. +""" + +import argparse +import json +import multiprocessing +import platform +import subprocess +import sys +import time +import traceback +from collections import OrderedDict +from pathlib import Path + +import numpy as np + +sys.path.insert(0, str(Path(__file__).parent.parent)) + +OLD_NDATA_CAP = 3300 # old per-LC kernel's shared-memory cap on ndata +REF_SKIP_DEFAULT = ('kepler-4yr',) # CPU ref >> 15 min; needs --ref-all + +# ---------------------------------------------------------------------------- +# Survey regimes (period ranges chosen for comparability with the reference +# TLS paper / GTLS 2026 paper). cadence in days; noise/depth fractional flux. +# ---------------------------------------------------------------------------- +MIN30 = 30.0 / (60.0 * 24.0) +MIN2 = 2.0 / (60.0 * 24.0) + +REGIMES = OrderedDict([ + ('tess-ffi', dict(ndata=1310, baseline=27.4, cadence=MIN30, noise=1e-3, + inject_period=7.7, inject_depth=0.005, + period_min=0.6, period_max=13.7, nlc=100)), + ('k2', dict(ndata=4320, baseline=90.0, cadence=MIN30, noise=8e-4, + inject_period=12.4, inject_depth=0.004, + period_min=0.6, period_max=45.0, nlc=50)), + ('tess-2min', dict(ndata=19710, baseline=27.4, cadence=MIN2, noise=2e-3, + inject_period=7.7, inject_depth=0.005, + period_min=0.6, period_max=13.7, nlc=50)), + ('tess-yr', dict(ndata=16850, baseline=351.0, cadence=MIN30, noise=1e-3, + inject_period=21.7, inject_depth=0.004, + period_min=0.6, period_max=175.0, nlc=20)), + ('kepler-4yr', dict(ndata=65440, baseline=1363.0, cadence=MIN30, + noise=6e-4, inject_period=41.3, inject_depth=0.003, + period_min=0.6, period_max=500.0, nlc=10)), +]) + + +# ---------------------------------------------------------------------------- +# Lightcurve generation +# ---------------------------------------------------------------------------- + +def make_lc(cfg, seed, inject): + """Regular-cadence LC, flux ~1.0, optional box transit at t0 = 0.3 * P + with Keplerian duration q = 0.0763 * P^(-2/3) (fraction of period, + Sun-like). A box (not limb-darkened) is fine: recovery is on period.""" + rng = np.random.default_rng(seed) + t = np.arange(cfg['ndata'], dtype=np.float64) * cfg['cadence'] + y = 1.0 + rng.normal(0.0, cfg['noise'], cfg['ndata']) + if inject: + P = cfg['inject_period'] + q = 0.0763 * P ** (-2.0 / 3.0) + t0 = 0.3 * P + in_transit = np.abs(((t - t0 + 0.5 * P) % P) - 0.5 * P) < 0.5 * q * P + y[in_transit] -= cfg['inject_depth'] + dy = np.full(cfg['ndata'], cfg['noise']) + return t, y, dy + + +def make_regime_lcs(key, cfg, nlc): + """~Half injected, half pure noise; seeded per (regime, lc_index).""" + regime_idx = list(REGIMES).index(key) + flags = [i % 2 == 0 for i in range(nlc)] + lcs = [make_lc(cfg, 100000 * (regime_idx + 1) + i, flags[i]) + for i in range(nlc)] + return lcs, flags + + +# ---------------------------------------------------------------------------- +# GPU / environment helpers (imports deferred so --help works anywhere) +# ---------------------------------------------------------------------------- + +def gpu_sync(): + try: + import pycuda.driver as drv + drv.Context.synchronize() + except Exception: + pass + + +def _get_device(): + try: # v1.0 lazy context helper + from cuvarbase.core import ensure_context + return ensure_context().device + except Exception: + import pycuda.autoprimaryctx + return pycuda.autoprimaryctx.device + + +def env_info(): + info = dict(python=platform.python_version(), numpy=np.__version__, + hostname=platform.node(), + cpu_count=multiprocessing.cpu_count()) + try: + import cuvarbase + info['cuvarbase'] = cuvarbase.__version__ + except Exception as e: + info['cuvarbase'] = 'unavailable: %s' % e + try: + import pycuda + import pycuda.driver as drv + dev = _get_device() + info['pycuda'] = getattr(pycuda, 'VERSION_TEXT', 'unknown') + info['cuda_driver_version'] = drv.get_driver_version() + info['gpu'] = dev.name() + info['compute_capability'] = '%d.%d' % dev.compute_capability() + except Exception as e: + info['gpu'] = 'unavailable: %s' % e + try: + out = subprocess.check_output(['nvcc', '--version'], + stderr=subprocess.STDOUT) + info['nvcc'] = out.decode().strip().splitlines()[-2].strip() + except Exception as e: + info['nvcc'] = 'unavailable: %s' % e + return info + + +def probe_nperiods(cfg): + """Number of Ofir-grid periods this regime's search covers.""" + try: + from cuvarbase import tls_grids + t = np.arange(cfg['ndata'], dtype=np.float64) * cfg['cadence'] + periods = tls_grids.period_grid_ofir( + t, R_star=1.0, M_star=1.0, oversampling_factor=3, + period_min=cfg['period_min'], period_max=cfg['period_max']) + return int(len(periods)) + except Exception as e: + print(' nperiods probe failed: %r' % e) + return None + + +# ---------------------------------------------------------------------------- +# Recovery / statistics +# ---------------------------------------------------------------------------- + +def _f(v): + try: + return float(v) + except Exception: + return None + + +def eval_recovery(results, flags, inject_period): + """Recovery on the injected half; |P/P_inj - 1| < 0.01 counts as + recovered, 2x / 0.5x aliases (1% relative) counted separately.""" + n_inj = n_rec = n_alias = 0 + sde_inj, sde_noise = [], [] + for res, injected in zip(results, flags): + res = res or {} + sde = _f(res.get('SDE')) + if injected: + n_inj += 1 + if sde is not None: + sde_inj.append(sde) + p = _f(res.get('period')) + if p: + r = p / inject_period + if abs(r - 1.0) < 0.01: + n_rec += 1 + elif abs(r / 2.0 - 1.0) < 0.01 or abs(2.0 * r - 1.0) < 0.01: + n_alias += 1 + elif sde is not None: + sde_noise.append(sde) + return dict( + n_injected=n_inj, n_recovered=n_rec, n_alias=n_alias, + recovery_frac=(n_rec / n_inj) if n_inj else None, + median_sde_injected=float(np.median(sde_inj)) if sde_inj else None, + median_sde_noise=float(np.median(sde_noise)) if sde_noise else None) + + +def compact_per_lc(results, flags): + out = [] + for res, injected in zip(results, flags): + res = res or {} + rec = dict(injected=bool(injected)) + for k in ('period', 'T0', 'duration', 'depth', 'SDE', 'chi2_min'): + rec[k] = _f(res.get(k)) + out.append(rec) + return out + + +# ---------------------------------------------------------------------------- +# Implementations +# ---------------------------------------------------------------------------- + +def _warmup_new(tls_search_batch, cfg): + """A 2-LC batch with the REGIME's own config so every phase-bin + band variant this regime needs is compiled before timing (band + structure depends on the period range).""" + print(' [new] warmup: 2-LC regime batch (absorbs compile)...', + flush=True) + wlcs = [make_lc(cfg, 900 + i, inject=True) for i in range(2)] + tls_search_batch(wlcs, R_star=1.0, M_star=1.0, + period_min=cfg['period_min'], + period_max=cfg['period_max'], + oversampling_factor=3, n_durations=15, + t0_oversample=3.0, + block_size=None, nbins=None, return_arrays=False) + gpu_sync() + + +def run_new(cfg, lcs, flags, args, state): + entry = dict(nlc=len(lcs)) + try: + from cuvarbase.tls import tls_search_batch + except Exception as e: + traceback.print_exc() + entry['error'] = 'import failed: %r' % e + return entry + try: + warm_key = 'new_warmed_%s_%s' % (cfg['period_min'], + cfg['period_max']) + if not state.get(warm_key): + _warmup_new(tls_search_batch, cfg) + state[warm_key] = True + print(' [new] timing %d-LC batch (x%d iter)...' + % (len(lcs), args.n_iter), flush=True) + times, results = [], None + for _ in range(args.n_iter): + gpu_sync() + t0 = time.perf_counter() + results = tls_search_batch( + lcs, R_star=1.0, M_star=1.0, + period_min=cfg['period_min'], period_max=cfg['period_max'], + oversampling_factor=3, n_durations=15, t0_oversample=3.0, + block_size=None, nbins=None, + return_arrays=False) + gpu_sync() + times.append(time.perf_counter() - t0) + total = float(np.median(times)) + entry.update(total_s=total, times_s=times, + ms_per_lc=1000.0 * total / len(lcs), + lc_per_s=len(lcs) / total) + entry.update(eval_recovery(results, flags, cfg['inject_period'])) + entry['per_lc'] = compact_per_lc(results, flags) + except Exception as e: + traceback.print_exc() + entry['error'] = repr(e) + return entry + + +def run_old(cfg, lcs, flags, args): + entry = dict() + if cfg['ndata'] > OLD_NDATA_CAP: + entry['skipped'] = 'ndata cap' + print(' [old] skipped: ndata=%d > %d (shared-memory cap)' + % (cfg['ndata'], OLD_NDATA_CAP)) + return entry + try: + from cuvarbase.tls import tls_transit + except Exception as e: + traceback.print_exc() + entry['error'] = 'import failed: %r' % e + return entry + n_old = min(args.old_nlc, len(lcs)) + sub, subflags = lcs[:n_old], flags[:n_old] + kwargs = dict(R_star=1.0, M_star=1.0, period_min=cfg['period_min'], + period_max=cfg['period_max'], use_fast=False) + try: + print(' [old] warmup (1 LC, absorbs compile)...', flush=True) + tls_transit(*sub[0], **kwargs) + gpu_sync() + print(' [old] timing %d LCs (per-LC loop)...' % n_old, flush=True) + per_call, results = [], [] + for (t, y, dy) in sub: + gpu_sync() + t0 = time.perf_counter() + results.append(tls_transit(t, y, dy, **kwargs)) + gpu_sync() + per_call.append(time.perf_counter() - t0) + med = float(np.median(per_call)) + entry.update(nlc=n_old, total_s=float(np.sum(per_call)), + per_call_s=per_call, ms_per_lc=1000.0 * med, + lc_per_s=1.0 / med, extrapolated=True, + note='per-LC median over %d LCs' % n_old) + entry.update(eval_recovery(results, subflags, cfg['inject_period'])) + entry['per_lc'] = compact_per_lc(results, subflags) + except Exception as e: + traceback.print_exc() + entry['error'] = repr(e) + return entry + + +def run_reference(key, cfg, lcs, flags, args): + entry = dict() + if key in REF_SKIP_DEFAULT and not args.ref_all: + entry['skipped'] = ('expected CPU runtime >~15 min; ' + 'pass --ref-all to run') + print(' [reference] skipped: %s' % entry['skipped']) + return entry + try: + from transitleastsquares import transitleastsquares + except Exception as e: + entry['error'] = 'import failed: %r' % e + print(' [reference] %s' % entry['error']) + return entry + n_ref = min(args.ref_nlc, len(lcs)) + sub, subflags = lcs[:n_ref], flags[:n_ref] + ncpu = multiprocessing.cpu_count() + try: + print(' [reference] timing %d LCs (CPU, %d threads)...' + % (n_ref, ncpu), flush=True) + per_call, results = [], [] + for (t, y, dy) in sub: + t0 = time.perf_counter() + # reference TLS expects flux normalized around 1.0; our + # generator already produces y ~ 1.0 + model = transitleastsquares(t, y, dy) + res = model.power(R_star=1.0, M_star=1.0, + period_min=cfg['period_min'], + period_max=cfg['period_max'], + oversampling_factor=3, use_threads=ncpu, + show_progress_bar=False) + per_call.append(time.perf_counter() - t0) + results.append({k: _f(getattr(res, k, None)) for k in + ('period', 'SDE', 'T0', 'duration', 'depth')}) + med = float(np.median(per_call)) + entry.update(nlc=n_ref, total_s=float(np.sum(per_call)), + per_call_s=per_call, ms_per_lc=1000.0 * med, + lc_per_s=1.0 / med, extrapolated=True, + note='per-LC median over %d LCs' % n_ref) + entry.update(eval_recovery(results, subflags, cfg['inject_period'])) + entry['per_lc'] = compact_per_lc(results, subflags) + except Exception as e: + traceback.print_exc() + entry['error'] = repr(e) + return entry + + +# ---------------------------------------------------------------------------- +# Reporting +# ---------------------------------------------------------------------------- + +def _row(key, impl, nlc, total, mslc, lcs, rec, notes): + print('%-11s %-10s %5s %10s %10s %9s %10s %s' + % (key, impl, nlc, total, mslc, lcs, rec, notes)) + + +def print_summary(out): + print('\n' + '=' * 96 + '\nSUMMARY\n' + '=' * 96) + _row('regime', 'impl', 'nlc', 'total s', 'ms/LC', 'LC/s', 'recovery', + 'notes') + print('-' * 96) + for key, regime in out['regimes'].items(): + for impl, e in regime['impls'].items(): + if 'skipped' in e: + _row(key, impl, *['-'] * 5, 'skipped: %s' % e['skipped']) + elif 'error' in e: + _row(key, impl, *['-'] * 5, + 'error: %s' % str(e['error'])[:40]) + else: + rec = '%d/%d' % (e.get('n_recovered', 0), + e.get('n_injected', 0)) + if e.get('n_alias'): + rec += '+%da' % e['n_alias'] + _row(key, impl, '%d' % e['nlc'], '%.3f' % e['total_s'], + '%.2f' % e['ms_per_lc'], '%.2f' % e['lc_per_s'], + rec, e.get('note', '')) + print('=' * 96) + + +# ---------------------------------------------------------------------------- +# Main +# ---------------------------------------------------------------------------- + +def parse_args(): + p = argparse.ArgumentParser( + description='Survey-scale TLS throughput benchmark (GPU)', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + p.add_argument('--regimes', default=','.join(REGIMES), + help='comma-separated regime keys') + p.add_argument('--nlc', type=int, default=None, + help='override per-regime lightcurve count') + p.add_argument('--impls', default='new,old', + help='comma-separated: new,old,reference') + p.add_argument('--ref-nlc', type=int, default=1, + help='LCs for the CPU reference implementation') + p.add_argument('--old-nlc', type=int, default=5, + help='LCs for the old per-LC GPU path (extrapolated)') + p.add_argument('--n-iter', type=int, default=1, + help='timed iterations per batch (median reported)') + p.add_argument('--output', default='tls_survey_bench_results.json') + p.add_argument('--quick', action='store_true', + help='smoke test: nlc=4 per regime') + p.add_argument('--ref-all', action='store_true', + help='run CPU reference on all regimes incl. kepler-4yr') + return p.parse_args() + + +def main(): + args = parse_args() + + regime_keys = [k.strip() for k in args.regimes.split(',') if k.strip()] + bad = [k for k in regime_keys if k not in REGIMES] + if bad: + sys.exit('unknown regime(s) %s; choose from %s' + % (bad, list(REGIMES))) + impls = [s.strip() for s in args.impls.split(',') if s.strip()] + bad = [s for s in impls if s not in ('new', 'old', 'reference')] + if bad: + sys.exit('unknown impl(s) %s; choose from new,old,reference' % bad) + + out = dict(script='benchmark_tls_survey.py', + timestamp=time.strftime('%Y-%m-%dT%H:%M:%S'), + args=vars(args), regimes=OrderedDict()) + state = {} + + for key in regime_keys: + cfg = dict(REGIMES[key]) + nlc = args.nlc if args.nlc else (4 if args.quick else cfg['nlc']) + print('\n' + '=' * 70) + print('%s: ndata=%d, baseline=%.1fd, P=[%.2g, %.4g]d, nlc=%d' + % (key, cfg['ndata'], cfg['baseline'], cfg['period_min'], + cfg['period_max'], nlc)) + print('=' * 70) + + lcs, flags = make_regime_lcs(key, cfg, nlc) + nperiods = probe_nperiods(cfg) + if nperiods: + print(' Ofir grid: %d periods' % nperiods) + + regime_entry = dict(config=cfg, nlc=nlc, nperiods=nperiods, + impls=OrderedDict()) + for impl in impls: + if impl == 'new': + e = run_new(cfg, lcs, flags, args, state) + elif impl == 'old': + e = run_old(cfg, lcs, flags, args) + else: + e = run_reference(key, cfg, lcs, flags, args) + if 'total_s' in e: + print(' [%s] total %.3f s | %.2f ms/LC | %.2f LC/s | ' + 'recovered %d/%d (+%d alias)' + % (impl, e['total_s'], e['ms_per_lc'], e['lc_per_s'], + e.get('n_recovered', 0), e.get('n_injected', 0), + e.get('n_alias', 0))) + regime_entry['impls'][impl] = e + out['regimes'][key] = regime_entry + + out['env'] = env_info() + print('\n' + json.dumps(out['env'], indent=2)) + + print_summary(out) + + with open(args.output, 'w') as f: + json.dump(out, f, indent=2, default=str) + print('wrote %s' % args.output) + + +if __name__ == '__main__': + main() diff --git a/scripts/gtls_benchmark/README.md b/scripts/gtls_benchmark/README.md new file mode 100644 index 0000000..b4d3e3f --- /dev/null +++ b/scripts/gtls_benchmark/README.md @@ -0,0 +1,39 @@ +# GTLS apples-to-apples benchmark + +Reproduces Figure 7 of the GTLS paper (Hu, Ge, Jin & Willis, arXiv:2607.00348) — +single-light-curve search time vs light-curve baseline — with the search held +**fair** across implementations, on one GPU. Full analysis and results: +`analysis/GTLS_COMPARISON.md`. + +## Files +- `bench_core.py` — GPU-independent core: light-curve injection (batman, Keplerian + duration), the shared Ofir period grid, and the one identical SDE re-scorer. +- `gtls_apples_bench.py` — the runner. Sweeps baselines × methods (GTLS full/skip8, + cuvarbase TLS matched/default, cuvarbase BLS kunimoto/sensible), matching period + grid, per-period duration window, epoch density, and injected transit; writes JSON. +- `plot_fig7.py` — merges result JSONs and renders the reproduced figure + tables. + +## Requirements (GPU host) +`cupy`, `pycuda`, `scikit-cuda`, `batman-package`, `numpy<2` (numba/gtls pin), +plus **both** cuvarbase feature branches merged: +- `feature/tls-fast-survey` — the improved TLS (`tls_search_batch`); +- `feature/bls-survey-speed` — the improved BLS (`eebls_gpu_batch`). + +The TLS-vs-GTLS curves run on `feature/tls-fast-survey` alone; the **BLS** curves +require `feature/bls-survey-speed` (otherwise stock BLS is timed and the numbers +will differ from the writeup). GTLS = `pip install gputls` (v0.5.1) + cupy. + +## Run +```bash +python gtls_apples_bench.py \ + --baselines 200,500,1000,1500,2000,3000 \ + --methods cuv_tls_matched,cuv_tls_default,cuv_bls_kunimoto,cuv_bls_matched \ + --cuv-reps 3 --out results_cuv.json +# GTLS (slow at long baselines — its runtime scales ~N^2.5): +python gtls_apples_bench.py --baselines 200,500,1000,1500 \ + --methods gtls_full,gtls_skip8 --gtls-reps 1 --out results_gtls.json +python plot_fig7.py fig7_reproduction.png results_cuv.json results_gtls.json +``` + +Result JSONs from the July 2026 A5000 run are in +`benchmarks/results/gtls_comparison_jul2026/`. diff --git a/scripts/gtls_benchmark/bench_core.py b/scripts/gtls_benchmark/bench_core.py new file mode 100644 index 0000000..f6a3fea --- /dev/null +++ b/scripts/gtls_benchmark/bench_core.py @@ -0,0 +1,182 @@ +"""Apples-to-apples GTLS vs cuvarbase (TLS + BLS) — shared, GPU-independent core. + +This module holds everything that does NOT touch a GPU: light-curve +injection (with a Keplerian-consistent duration so BOTH search grids bracket +the true transit), the single shared Ofir period grid fed to every method, +an identical-SDE recompute so all methods are scored by the same statistic, +and the timing bookkeeping. The GPU method calls live in the runner. + +Design decisions (fairness): +- ONE light curve per baseline, fed to every method -> identical SNR by + construction (the comparison between methods can never differ in SNR). +- Injected transit uses Kepler's 3rd law for a(P) so its duration equals the + physically expected Keplerian duration -> it lands inside cuvarbase's + narrow 0.5-2x-Earth q band AND inside GTLS's wide duration grid. Neither + method is handed a transit its grid cannot represent. +- ONE Ofir period grid (period_grid_ofir) is generated once and passed to + gtls.power(periods=...), tls_search_batch(periods=...) and the BLS search, + so the period axis is bit-identical across methods. +- SDE is recomputed with the SAME function on every method's chi2(P) spectrum. +""" +import importlib.util +import numpy as np + +import os + + +def _load(name, path): + spec = importlib.util.spec_from_file_location(name, path) + m = importlib.util.module_from_spec(spec) + spec.loader.exec_module(m) + return m + + +# Prefer the installed package (pod / any env with cuvarbase importable); +# fall back to loading the single numpy-only module by path (local, no pycuda). +try: + from cuvarbase import tls_grids +except Exception: + _CUV = os.environ.get("CUVARBASE_DIR", + "/Users/johnhoffman/Documents/cuvarbase/cuvarbase") + tls_grids = _load("tls_grids", _CUV + "/tls_grids.py") + +# Physical constants (SI) for Kepler's third law +_G = 6.67430e-11 +_MSUN = 1.98840e30 +_RSUN = 6.95700e8 +_SPD = 86400.0 + + +def keplerian_a_over_Rstar(period_days, M_star=1.0, R_star=1.0): + """a/R_star for a circular orbit from Kepler's third law.""" + P = period_days * _SPD + a_m = (_G * M_star * _MSUN * P**2 / (4.0 * np.pi**2))**(1.0 / 3.0) + return a_m / (R_star * _RSUN) + + +def transit_snr(depth, noise, period, duration_days, baseline_days, cadence_days): + """Total transit SNR ~ (depth/noise) * sqrt(N_in_transit_total).""" + n_transits = max(1, int(np.floor(baseline_days / period))) + pts_per_transit = duration_days / cadence_days + n_in = n_transits * pts_per_transit + return depth / noise * np.sqrt(max(n_in, 1.0)) + + +def make_lc(baseline_days, cadence_days, period, depth, noise, seed, + M_star=1.0, R_star=1.0, u=(0.4804, 0.1867), inject=True): + """Regular-cadence LC with an optional batman limb-darkened transit whose + a/R_star follows Kepler's 3rd law (=> physical Keplerian duration). + + batman is only available on the GPU pod; imported lazily so this module + loads locally for grid/SDE checks. + """ + import batman + rng = np.random.RandomState(seed) + n = int(round(baseline_days / cadence_days)) + t = np.arange(n) * cadence_days + y = 1.0 + rng.randn(n) * noise + dy = np.full(n, noise, dtype=float) + meta = dict(ndata=n, period=period, depth=depth, noise=noise, + baseline=baseline_days, cadence=cadence_days) + if inject: + a = keplerian_a_over_Rstar(period, M_star, R_star) + t0 = 0.35 * period + t.min() + pm = batman.TransitParams() + pm.t0 = t0 + pm.per = period + pm.rp = float(np.sqrt(depth)) # depth ~ (Rp/Rs)^2 + pm.a = float(a) + pm.inc = 90.0 + pm.ecc = 0.0 + pm.w = 90.0 + pm.u = list(u) + pm.limb_dark = "quadratic" + m = batman.TransitModel(pm, t) + y = y + (m.light_curve(pm) - 1.0) + # physical T14 (edge-on) for bookkeeping / grid-bracket check + b = 0.0 + T14 = period / np.pi * np.arcsin( + 1.0 / a * np.sqrt((1.0 + pm.rp)**2 - b**2)) + meta.update(t0=t0, a_over_Rstar=a, T14_days=float(T14), + q_true=float(T14 / period), + snr=float(transit_snr(depth, noise, period, T14, + baseline_days, cadence_days))) + return t, y, dy, meta + + +def shared_period_grid(t, oversampling_factor=3, period_min=0.6, + period_max=None): + """The single Ofir grid every method searches (Pmax defaults to S/2).""" + return tls_grids.period_grid_ofir( + t, R_star=1.0, M_star=1.0, oversampling_factor=oversampling_factor, + period_min=period_min, period_max=period_max) + + +def recompute_sde_from_sr(sr, periods, oversampling_factor=3): + """The one identical SDE routine. Takes a signal-residue spectrum SR(P) + (large = better fit) already ascending in period. SDE = detrended-SR peak + z-score with a median filter (window = OS*30, TLS convention, odd, capped + at 91). Every method is scored through THIS function so the statistic is + identical; only the spectrum differs.""" + from scipy.signal import medfilt + sr = np.asarray(sr, dtype=float) + p = np.asarray(periods, dtype=float) + ok = np.isfinite(sr) & np.isfinite(p) + sr, p = sr[ok], p[ok] + if sr.size < 5: + return dict(SDE=0.0, best_period=float("nan"), depth_snr=0.0) + w = min(int(oversampling_factor * 30), 91) + if w % 2 == 0: + w += 1 + trend = medfilt(sr, kernel_size=w) if (3 <= w < len(sr)) \ + else np.zeros_like(sr) + resid = sr - trend + sd = resid.std() + SDE = resid / sd if sd > 0 else resid * 0.0 + ibest = int(np.argmax(SDE)) + return dict(SDE=float(SDE[ibest]), best_period=float(p[ibest]), + sr_max=float(np.nanmax(sr))) + + +def recompute_sde(chi2, periods, oversampling_factor=3): + """Score a chi2(period) spectrum: SR = 1 - chi2/chi2_null(=max), then the + identical SDE routine above.""" + chi2 = np.asarray(chi2, dtype=float) + ok = np.isfinite(chi2) & (chi2 < 1e29) + c = chi2[ok] + p = np.asarray(periods, dtype=float)[ok] + if c.size < 5: + return dict(SDE=0.0, best_period=float("nan"), depth_snr=0.0) + chi2_null = np.nanmax(c) + out = recompute_sde_from_sr(1.0 - c / chi2_null, p, oversampling_factor) + out["depth_snr"] = float(np.sqrt(max(chi2_null - np.nanmin(c), 0.0))) + out["chi2_min"] = float(np.nanmin(c)) + return out + + +def recovered(p_found, p_true, tol=0.02): + for k in (1.0, 2.0, 0.5, 3.0, 1 / 3.0): + if abs(p_found - k * p_true) / (k * p_true) < tol: + return True + return False + + +if __name__ == "__main__": + # Local self-test of the fairness invariants (no GPU, no batman needed + # for the grid parts). + for base in (200, 1500, 3000): + cad = 30.0 / 60 / 24 + t = np.arange(int(base / cad)) * cad + pg = shared_period_grid(t) + # pick a period giving >=3 transits even at the shortest baseline + P = 8.13 + a = keplerian_a_over_Rstar(P) + T14 = P / np.pi * np.arcsin(1.0 / a * np.sqrt((1 + 0.05)**2)) + q = T14 / P + # is q inside cuvarbase's 0.5-2x Earth band at this period? + _, _, qvals = tls_grids.duration_grid_keplerian( + np.array([P]), 1.0, 1.0, 1.0, n_durations=15) + band = (0.5 * qvals[0], 2.0 * qvals[0]) + print(f"base={base:5d} Npg={len(pg):7d} P={P} T14={T14*24:.2f}h " + f"q_true={q:.4f} cuvar_band=[{band[0]:.4f},{band[1]:.4f}] " + f"in_band={band[0] <= q <= band[1]}") diff --git a/scripts/gtls_benchmark/cold_driver.sh b/scripts/gtls_benchmark/cold_driver.sh new file mode 100644 index 0000000..4a3ed38 --- /dev/null +++ b/scripts/gtls_benchmark/cold_driver.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# TRUE cold single-shot: clear the on-disk kernel caches before EACH run so the +# JIT compile happens from scratch every time (first-run / fresh-container case). +# Each (method, baseline) is a fresh process. Reports full_wall (python import + +# CUDA context init + compile + search) and search_compile (compile + search). +export PATH=/usr/local/cuda/bin:$PATH +cd /root +printf "%-17s %6s %11s %13s %8s %6s\n" method baseline full_wall_s search_compile nper SDE +for base in 200 500 1000 1500; do + for m in cuv_tls_default cuv_tls_matched gtls_skip8; do + rm -rf ~/.cache/pycuda /root/.cache/pycuda ~/.cupy ~/.nv/ComputeCache 2>/dev/null + t0=$(date +%s.%N) + OUT=$(python3 cold_shot.py --method "$m" --baseline "$base" 2>/dev/null | grep RESULT) + t1=$(date +%s.%N) + wall=$(awk "BEGIN{printf \"%.2f\", $t1-$t0}") + sc=$(echo "$OUT" | grep -oE 'search_compile_s=[0-9.]+' | cut -d= -f2) + nper=$(echo "$OUT" | grep -oE 'nper=[0-9]+' | cut -d= -f2) + sde=$(echo "$OUT" | grep -oE 'SDE=[0-9.]+' | cut -d= -f2) + printf "%-17s %6d %11s %13s %8s %6s\n" "$m" "$base" "$wall" "${sc:-ERR}" "${nper:-?}" "${sde:-?}" + done +done +echo "DONE_COLD" diff --git a/scripts/gtls_benchmark/cold_shot.py b/scripts/gtls_benchmark/cold_shot.py new file mode 100644 index 0000000..8f00216 --- /dev/null +++ b/scripts/gtls_benchmark/cold_shot.py @@ -0,0 +1,96 @@ +"""Cold single-shot timing: one light curve, one fresh process, NO warmup, so +the kernel JIT compile is INCLUDED for both cuvarbase and GTLS. The CUDA context +is initialized before the clock starts (a fixed driver cost both pay), so the +measured number is compile + search — the true one-star cold cost. The launching +shell also times the whole process (python import + context init + this). + +Standalone Ofir grid + LC (numpy/batman only) so the GTLS process never imports +cuvarbase (fair: each loads only its own stack). + +Usage: python cold_shot.py --method {gtls_skip8|cuv_tls_matched|cuv_tls_default} --baseline 1500 +""" +import argparse +import time +import warnings +warnings.filterwarnings("ignore") +import numpy as np + +G = 6.67430e-11; RSUN = 6.957e8; MSUN = 1.9884e30; SPD = 86400.0; RJUP = 6.9911e7 + + +def ofir_grid(t, os=3, pmin=0.6, n_transits_min=2): + T = (t.max() - t.min()) * SPD + fmin = n_transits_min / T + fmax = 1 / (2 * np.pi) * np.sqrt(G * MSUN / (3 * RSUN) ** 3) + A = (2 * np.pi) ** (2 / 3) / np.pi * RSUN / (G * MSUN) ** (1 / 3) / (T * os) + C = fmin ** (1 / 3) - A / 3 + n = int(np.ceil((fmax ** (1 / 3) - fmin ** (1 / 3) + A / 3) * 3 / A)) + x = np.arange(n) + 1 + per = 1 / ((A / 3 * x + C) ** 3) / SPD + return np.sort(per[per > pmin]) + + +def make_lc(baseline, cad=30 / 60 / 24, P=8.13, depth=4e-3, noise=4e-3, seed=1): + import batman + rng = np.random.RandomState(seed) + n = int(round(baseline / cad)); t = np.arange(n) * cad + y = 1 + rng.randn(n) * noise; dy = np.full(n, noise) + a = (G * MSUN * (P * SPD) ** 2 / (4 * np.pi ** 2)) ** (1 / 3) / RSUN + pm = batman.TransitParams() + pm.t0 = 0.35 * P; pm.per = P; pm.rp = float(np.sqrt(depth)); pm.a = float(a) + pm.inc = 90; pm.ecc = 0; pm.w = 90; pm.u = [0.4804, 0.1867] + pm.limb_dark = "quadratic" + y = y + (batman.TransitModel(pm, t).light_curve(pm) - 1) + return t, y, dy + + +def gtls_qwin(P): + Ps = P * SPD + pfmin = 4 * Ps / (20848 * 1e15); pfmax = 4 * Ps / (416970 * 1e15) + dmin = np.minimum((RSUN * 0.05) * pfmin ** (1 / 3) / Ps, 0.15) + dmax = np.minimum((RSUN * 4.0 + 2 * RJUP) * pfmax ** (1 / 3) / Ps, 0.15) + dmin = np.clip(dmin, 1e-5, 0.15 * 0.999); dmax = np.clip(dmax, dmin * 1.0001, 0.999) + return dmin, dmax + + +ap = argparse.ArgumentParser() +ap.add_argument("--method", required=True) +ap.add_argument("--baseline", type=int, required=True) +args = ap.parse_args() + +t, y, dy = make_lc(args.baseline) +periods = ofir_grid(t) + +if args.method.startswith("gtls"): + import cupy as cp + cp.arange(1).sum(); cp.cuda.Stream.null.synchronize() # init context (untimed) + from gputls import gtls + t0fit = 0.0 if args.method == "gtls_full" else 0.125 + c0 = time.perf_counter() + res = gtls(t=t, y=y, dy=dy, verbose=False).power( + periods=periods, R_star=1, M_star=1, oversampling_factor=3, + T0_fit_margin=t0fit, verbose=False, show_progress_bar=False) + cp.cuda.Stream.null.synchronize() + dt = time.perf_counter() - c0 + print("RESULT %s %d nper=%d search_compile_s=%.3f P=%.4f SDE=%.2f" + % (args.method, args.baseline, len(periods), dt, res.period, res.SDE)) +else: + import pycuda.autoprimaryctx # init context at import (untimed) + import pycuda.driver as drv + drv.Context.synchronize() + from cuvarbase.tls import tls_search_batch + if args.method == "cuv_tls_matched": + qmn, qmx = gtls_qwin(periods) + kw = dict(qmin=qmn, qmax=qmx, n_durations=38, t0_oversample=8.0) + else: + kw = dict(n_durations=15, t0_oversample=3.0) + c0 = time.perf_counter() + res = tls_search_batch([(t, y, dy)], R_star=1, M_star=1, periods=periods, + oversampling_factor=3, refine_top_k=50, + u=[0.4804, 0.1867], limb_dark="quadratic", + return_arrays=False, **kw)[0] + drv.Context.synchronize() + dt = time.perf_counter() - c0 + print("RESULT %s %d nper=%d search_compile_s=%.3f P=%.4f SDE=%.2f" + % (args.method, args.baseline, len(periods), dt, + res.get("period", -1), res.get("SDE", -1))) diff --git a/scripts/gtls_benchmark/gtls_apples_bench.py b/scripts/gtls_benchmark/gtls_apples_bench.py new file mode 100644 index 0000000..d72e99b --- /dev/null +++ b/scripts/gtls_benchmark/gtls_apples_bench.py @@ -0,0 +1,393 @@ +#!/usr/bin/env python +"""Apples-to-apples reproduction of GTLS paper (arXiv:2607.00348) Figure 7: +runtime vs light-curve baseline for GTLS vs cuvarbase TLS vs cuvarbase BLS, +all on the SAME GPU, SAME light curve, SAME period grid, SAME per-period +duration search extent, SAME epoch (t0) density, and (optionally) the SAME +limb-darkened template. Every method is additionally scored by ONE identical +SDE routine so we can confirm equal detection, not just equal speed. + +Fairness protocol (see notes at bottom): + * ONE injected batman transit per baseline, fed to every method -> identical + SNR between methods by construction. + * ONE Ofir period grid (cuvarbase.tls_grids.period_grid_ofir, Pmax=S/2) + passed explicitly to gtls.power(periods=), tls_search_batch(periods=), + and BLS (freqs=sort(1/periods)). + * cuvarbase-TLS "matched" uses per-period qmin/qmax = GTLS's own kernel + duration window and n_durations chosen for the same log-1.1 resolution + (~38), and t0_oversample matched to GTLS's SKIP_POINT (=1/T0_fit_margin). + * cuvarbase-TLS "default" is the shipping survey default (t0_os=3, 15 dur, + Keplerian [0.5q,2q]) — the "production" number, clearly separated. + * BLS uses the paper's Kunimoto params (qmin=2e-4, qmax=0.15, dlogq=0.1, + noverlap=3) on the identical period grid. + +Runs on a GPU pod with: cupy, gputls, cuvarbase (TLS branch + BLS branch +merged), batman, numpy, scipy. + +Usage: + python gtls_apples_bench.py --baselines 200,500,1000,1500,2000,3000 \ + --methods gtls_full,gtls_skip8,cuv_tls_matched,cuv_tls_default,cuv_bls \ + --out results.json +""" +import argparse +import gc +import json +import platform +import time +import traceback +import warnings + +warnings.filterwarnings("ignore") +import numpy as np + +# ---- shared, GPU-independent helpers (LC gen, grid, identical-SDE) ---------- +import bench_core as bc # co-located module + +CAD = 30.0 / 60.0 / 24.0 # 30-min Kepler long cadence, days +# Injected transit (fixed across baselines; a from Kepler's 3rd law -> physical +# Keplerian duration so BOTH search grids bracket it): +INJ_PERIOD = 8.13 +INJ_DEPTH = 0.004 +INJ_NOISE = 0.004 +INJ_U = (0.4804, 0.1867) # G2V Kepler LD (== GTLS/TLS reference) + +# ---- GTLS per-period duration window (from GPUFun.py durationsGrid kernel) -- +_R_SUN = 695508000.0 +_R_JUP = 69911000.0 +_SPD = 86400.0 +_SCALE = 1e15 +_PI_GM_MIN = 20848.0 +_PI_GM_MAX = 416970.0 +_RS_MIN = _R_SUN * 0.05 +_RS_MAX = _R_SUN * 4.0 +_FRAC_MAX = 0.15 + + +def gtls_dur_window(P_days): + """Vectorized GTLS per-period (qmin,qmax) fractional-duration window.""" + P = np.asarray(P_days, float) + Ps = P * _SPD + pf_min = (4.0 * Ps) / (_PI_GM_MIN * _SCALE) + pf_max = (4.0 * Ps) / (_PI_GM_MAX * _SCALE) + T14Min = _RS_MIN * pf_min ** (1.0 / 3.0) + T14Max = (_RS_MAX + _R_JUP * 2.0) * pf_max ** (1.0 / 3.0) + dmin = np.minimum(T14Min / Ps, _FRAC_MAX) + dmax = np.minimum(T14Max / Ps, _FRAC_MAX) + # guard qmin>0 and qmin impact parameter b = a*cos(inc) ~ 0.32 + p.ecc = 0.0 + p.w = 90.0 + p.limb_dark = limb_dark + p.u = list(u) + # transit half-width in phase ~ (1/pi)*asin(sqrt((1+rp)^2-b^2)/a); span it + tt = np.linspace(-0.05, 0.05, n_samples) + m = batman.TransitModel(p, tt) + flux = m.light_curve(p) + oot = flux[0] + depth = oot - np.min(flux) + if depth < 1e-10: + raise ValueError("template depth ~0") + fluxn = (flux - oot) / depth + 1.0 + phases = (tt - tt[0]) / (tt[-1] - tt[0]) + return phases, fluxn + + tm.create_reference_transit = hippke_reference + return True + + +def run_cuv_tls(lcs, periods, t0_oversample, qmin, qmax, n_durations, + u=INJ_U, reps=3, label="cuv_tls"): + from cuvarbase.tls import tls_search_batch + periods = np.sort(np.asarray(periods, float)) + + kw = dict(R_star=1.0, M_star=1.0, periods=periods, + oversampling_factor=3, n_durations=n_durations, + t0_oversample=t0_oversample, refine_top_k=50, + u=list(u), limb_dark="quadratic", return_arrays=True) + if qmin is not None: + kw["qmin"] = np.asarray(qmin, float) + kw["qmax"] = np.asarray(qmax, float) + + def call(): + return tls_search_batch(lcs, **kw) + + total_s, ts, res = timed(_pycuda_sync, call, warmups=1, reps=reps) + # per-LC = batch time / n_lcs (single-LC head-to-head when len(lcs)==1) + per_lc = total_s / len(lcs) + r0 = res[0] + if "error" in r0: + return dict(method=label, time_s=per_lc, error=r0["error"]) + sde = bc.recompute_sde(np.asarray(r0["chi2"], float), + np.asarray(r0["periods"], float)) + return dict(method=label, time_s=per_lc, batch_time_s=total_s, times_s=ts, + n_lcs=len(lcs), t0_oversample=t0_oversample, + n_durations=n_durations, period_native=float(r0["period"]), + sde_native=float(r0["SDE"]), sde_identical=sde["SDE"], + best_period_identical=sde["best_period"], + depth_snr=sde["depth_snr"], + recovered=bc.recovered(sde["best_period"], INJ_PERIOD), + recovered_native=bc.recovered(float(r0["period"]), INJ_PERIOD), + n_periods=int(len(periods))) + + +# --------------------------------------------------------- cuvarbase BLS ------ +def run_cuv_bls(lcs, periods, cfg="kunimoto", reps=3, label="cuv_bls"): + """BLS on the identical period grid. eebls_gpu_batch returns only power + spectra -> argmax for the identical-SDE score. + + cfg='kunimoto': the GTLS paper's BLS config (qmin=2e-4, qmax=0.15, + dlogq=0.1, noverlap=3) -> up to 5000 phase bins, fused kernel bypassed. + cfg='matched': BLS duration grid matched to the TLS run's per-period + window (qmin/qmax = GTLS window) with noverlap=2 so the fused kernel + (opt1) is used -> BLS's true speed at TLS-comparable duration fidelity. + """ + from cuvarbase.bls import eebls_gpu_batch + periods = np.sort(np.asarray(periods, float)) + freqs = np.sort((1.0 / periods).astype(np.float32)) + if cfg == "kunimoto": + kw = dict(qmin=2e-4, qmax=0.15, dlogq=0.1, noverlap=3) + elif cfg == "matched": + # BLS at a physically sensible transit-duration range (>=0.2% of the + # period, brackets the injected q~0.02) with the fused kernel + # (noverlap=2, power of two). This is BLS's true competitive speed; + # the Kunimoto qmin=2e-4 (5000 bins) is what makes 'kunimoto' heavy. + kw = dict(qmin=2e-3, qmax=0.15, dlogq=0.1, noverlap=2) + else: + raise ValueError(cfg) + + def call(): + return eebls_gpu_batch(lcs, freqs, **kw) + + total_s, ts, powers = timed(_pycuda_sync, call, warmups=1, reps=reps) + per_lc = total_s / len(lcs) + p0 = np.asarray(powers[0], float) + ok = np.isfinite(p0) + fr = freqs[ok].astype(float) + order = np.argsort(1.0 / fr) # ascending period + sde = bc.recompute_sde_from_sr(p0[ok][order], (1.0 / fr)[order]) + scal = {k: (float(np.median(v)) if hasattr(v, "__len__") else v) + for k, v in kw.items()} + return dict(method=label, cfg=cfg, time_s=per_lc, batch_time_s=total_s, + times_s=ts, n_lcs=len(lcs), n_periods=int(len(periods)), + sde_identical=sde["SDE"], best_period_identical=sde["best_period"], + recovered=bc.recovered(sde["best_period"], INJ_PERIOD), + qcfg=scal) + + +# ------------------------------------------------------------------ main ------ +def env_info(): + info = dict(python=platform.python_version(), numpy=np.__version__, + host=platform.node()) + try: + import cupy as cp + info["cupy"] = cp.__version__ + info["gpu"] = cp.cuda.runtime.getDeviceProperties(0)["name"].decode() + info["cc"] = str(cp.cuda.Device(0).compute_capability) + info["gpu_mem_GB"] = round(cp.cuda.Device(0).mem_info[1] / 1e9, 1) + except Exception as e: + info["gpu"] = "cupy/gpu unavailable: %r" % e + for pkg in ("gputls", "cuvarbase", "batman"): + try: + m = __import__(pkg) + info[pkg] = getattr(m, "__version__", "?") + except Exception as e: + info[pkg] = "unavailable: %r" % e + return info + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--baselines", default="200,500,1000,1500,2000,3000") + ap.add_argument("--methods", + default="gtls_full,gtls_skip8,cuv_tls_matched," + "cuv_tls_default,cuv_bls") + ap.add_argument("--match-template", action="store_true", + help="patch cuvarbase template to Hippke geometry") + ap.add_argument("--gtls-reps", type=int, default=1) + ap.add_argument("--cuv-reps", type=int, default=3) + ap.add_argument("--out", default="gtls_apples_results.json") + args = ap.parse_args() + + baselines = [int(x) for x in args.baselines.split(",") if x] + methods = [m.strip() for m in args.methods.split(",") if m.strip()] + + if args.match_template and any(m.startswith("cuv_tls") for m in methods): + maybe_patch_template() + print("[template] cuvarbase reference transit patched to Hippke geometry") + + out = dict(script="gtls_apples_bench.py", + timestamp=time.strftime("%Y-%m-%dT%H:%M:%S"), + inj=dict(period=INJ_PERIOD, depth=INJ_DEPTH, noise=INJ_NOISE, + u=list(INJ_U), cadence_days=CAD), + match_template=args.match_template, baselines=baselines, + results={}) + + for base in baselines: + print("\n" + "=" * 72) + print("BASELINE %d d" % base) + print("=" * 72, flush=True) + t, y, dy, meta = bc.make_lc(base, CAD, INJ_PERIOD, INJ_DEPTH, + INJ_NOISE, seed=1000 + base, u=INJ_U) + periods = bc.shared_period_grid(t) + qmin, qmax = gtls_dur_window(periods) + n_dur_matched = gtls_matched_n_durations(periods) + print(" ndata=%d nperiods=%d SNR=%.1f q_true=%.4f " + "n_dur_matched=%d" % (meta["ndata"], len(periods), + meta.get("snr", -1), meta.get("q_true", -1), n_dur_matched), + flush=True) + row = dict(meta=meta, nperiods=int(len(periods)), + n_dur_matched=n_dur_matched, methods={}) + + for m in methods: + try: + if m == "gtls_full": + r = run_gtls(t, y, dy, periods, 0.0, reps=args.gtls_reps) + elif m == "gtls_skip8": + r = run_gtls(t, y, dy, periods, 0.125, reps=args.gtls_reps) + elif m == "cuv_tls_matched": + r = run_cuv_tls([(t, y, dy)], periods, t0_oversample=8.0, + qmin=qmin, qmax=qmax, + n_durations=n_dur_matched, + reps=args.cuv_reps, label="cuv_tls_matched") + elif m == "cuv_tls_default": + r = run_cuv_tls([(t, y, dy)], periods, t0_oversample=3.0, + qmin=None, qmax=None, n_durations=15, + reps=args.cuv_reps, label="cuv_tls_default") + elif m in ("cuv_bls", "cuv_bls_kunimoto"): + r = run_cuv_bls([(t, y, dy)], periods, cfg="kunimoto", + reps=args.cuv_reps, label=m) + elif m == "cuv_bls_matched": + r = run_cuv_bls([(t, y, dy)], periods, cfg="matched", + reps=args.cuv_reps, label=m) + else: + print(" unknown method %s" % m); continue + row["methods"][m] = r + print(" %-18s %9.3f s/LC SDE(id)=%6.2f P=%.4f rec=%s" + % (m, r.get("time_s", float("nan")), + r.get("sde_identical", float("nan")), + r.get("best_period_identical", float("nan")), + r.get("recovered")), flush=True) + except Exception as e: + traceback.print_exc() + row["methods"][m] = dict(error=repr(e)) + print(" %-18s ERROR %r" % (m, e), flush=True) + gc.collect() + + out["results"][str(base)] = row + with open(args.out, "w") as f: + json.dump(out, f, indent=2, default=str) + + out["env"] = env_info() + with open(args.out, "w") as f: + json.dump(out, f, indent=2, default=str) + print("\nwrote %s" % args.out) + print(json.dumps(out["env"], indent=2)) + + +if __name__ == "__main__": + main() diff --git a/scripts/gtls_benchmark/plot_fig7.py b/scripts/gtls_benchmark/plot_fig7.py new file mode 100644 index 0000000..01cbe41 --- /dev/null +++ b/scripts/gtls_benchmark/plot_fig7.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +"""Reproduce GTLS paper (arXiv:2607.00348) Fig. 7 apples-to-apples on one GPU, +plus an SDE-parity panel. Merges any number of results_*.json files (e.g. +results_cuv.json results_gtls.json). Writes fig7_reproduction.png. + +Usage: python plot_fig7.py out.png results_cuv.json results_gtls.json ... +""" +import json +import sys +import numpy as np +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt +from matplotlib.ticker import ScalarFormatter, NullFormatter + +OUT = sys.argv[1] if len(sys.argv) > 1 else "fig7_reproduction.png" +FILES = sys.argv[2:] or ["results_cuv.json", "results_gtls.json"] + +# merge: baseline -> method -> result +merged, gpu, inj = {}, "GPU", {} +for fn in FILES: + try: + d = json.load(open(fn)) + except Exception: + continue + gpu = d.get("env", {}).get("gpu", gpu) + inj = d.get("inj", inj) + for b, row in d.get("results", {}).items(): + merged.setdefault(b, {}) + for m, r in row.get("methods", {}).items(): + merged[b][m] = r + +bl = sorted(int(b) for b in merged) + +STYLE = { # colorblind-safe; grouped by family + "gtls_full": ("#d55e00", "o", "-", "GTLS full-T0 scan (paper Fig.7 setting)"), + "gtls_skip8": ("#e69f00", "s", "-", "GTLS skip=8 (its efficient default)"), + "cuv_bls_kunimoto": ("#cc79a7", "P", "-", "cuvarbase BLS (Kunimoto qmin=2e-4, nov=3 — paper's BLS cfg)"), + "cuv_tls_matched": ("#0072b2", "D", "-", "cuvarbase TLS (matched: grid+durations+epochs to GTLS)"), + "cuv_tls_default": ("#009e73", "^", "-", "cuvarbase TLS (survey default: t0os=3, 15 dur)"), + "cuv_bls_matched": ("#56b4e9", "v", "-", "cuvarbase BLS (sensible cfg: qmin=2e-3, fused nov=2)"), +} +ORDER = ["gtls_full", "gtls_skip8", "cuv_bls_kunimoto", "cuv_tls_matched", + "cuv_tls_default", "cuv_bls_matched"] + +def series(m, key): + xs, ys = [], [] + for b in bl: + v = merged[str(b)].get(m, {}).get(key) + if isinstance(v, (int, float)) and np.isfinite(v): + xs.append(b); ys.append(v) + return np.array(xs, float), np.array(ys, float) + +# published paper anchors (single-LC; GTLS/BLS on RTX 4090, TLS on 7950X CPU) +PAPER = {"gtls": [(1500, 33.3), (3000, 138.0)], "bls": [(1500, 121.1)], + "tls_cpu": [(1500, 522.0), (3000, 3289.0)]} + +fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9.6, 10.2), + gridspec_kw={"height_ratios": [2.5, 1]}) + +for m in ORDER: + c, mk, ls, lab = STYLE[m] + x, y = series(m, "time_s") + if len(x): + ax1.plot(x, y, marker=mk, ls=ls, color=c, lw=2, ms=7, label=lab, zorder=4) +# GTLS full compile-subtracted (search only) +xs, ys = series("gtls_full", "search_s") +if len(xs): + ax1.plot(xs, ys, ":", color=STYLE["gtls_full"][0], lw=1.3, alpha=.7, + label="GTLS full, search only (JIT-compile subtracted)", zorder=3) +# published paper points +px, py = zip(*PAPER["gtls"]); ax1.scatter(px, py, marker="*", s=280, + facecolor="none", edgecolor="#d55e00", linewidths=2, zorder=6) +bx, by = zip(*PAPER["bls"]); ax1.scatter(bx, by, marker="*", s=280, + facecolor="none", edgecolor="#cc79a7", linewidths=2, zorder=6) +tx, ty = zip(*PAPER["tls_cpu"]); ax1.plot(tx, ty, "--", color="#7f7f7f", lw=1.6, + marker="X", ms=10, label="reference TLS (CPU 7950X, paper)", zorder=3) +ax1.scatter([], [], marker="*", s=200, facecolor="none", edgecolor="k", + linewidths=1.5, label="★ published paper value (RTX 4090)") + +ax1.set_xscale("log"); ax1.set_yscale("log") +ax1.set_xlabel("light-curve baseline [days] (30-min cadence)") +ax1.set_ylabel("search time per light curve [s]") +snr = inj.get("period"), inj.get("depth") +ax1.set_title("GTLS Fig. 7 reproduced apples-to-apples on one GPU (%s)\n" + "identical Ofir period grid · identical per-period duration window " + "· matched epoch density · one injected transit" % gpu, fontsize=10.5) +ax1.grid(True, which="both", alpha=.25) +ax1.legend(fontsize=7.6, loc="lower right", framealpha=.96, ncol=1) +for b in (1500, 3000): + ax1.axvline(b, color="k", alpha=.06, lw=10) + +for m in ORDER: + c, mk, ls, lab = STYLE[m] + x, y = series(m, "sde_identical") + if len(x): + ax2.plot(x, y, marker=mk, color=c, lw=1.5, ms=6) +ax2.axhline(7, color="k", ls="--", lw=1, alpha=.6) +ax2.text(bl[0], 8, "SDE=7 detection threshold", fontsize=8, alpha=.7) +ax2.set_xscale("log") +ax2.set_xlabel("light-curve baseline [days]") +ax2.set_ylabel("SDE (one identical\nstatistic per spectrum)") +ax2.set_title("Detection significance is identical across all methods — " + "the speed gap is not bought with sensitivity", fontsize=10) +ax2.grid(True, which="both", alpha=.25) +# explicit x ticks (log axis otherwise only labels 10^3) +ticks = [b for b in (200, 300, 500, 1000, 1500, 2000, 3000) if bl[0] <= b <= bl[-1]] +for ax in (ax1, ax2): + ax.set_xticks(ticks) + ax.get_xaxis().set_major_formatter(ScalarFormatter()) + ax.get_xaxis().set_minor_formatter(NullFormatter()) + ax.set_xlim(bl[0] * 0.9, bl[-1] * 1.12) +fig.tight_layout() +fig.savefig(OUT, dpi=145, bbox_inches="tight") +print("wrote", OUT) + +# ---- text table + speedups ---- +hdr = "baseline " + "".join("%18s" % m.replace("cuv_", "").replace("_", " ") + for m in ORDER) +print("\n" + hdr) +for b in bl: + r = "%6dd " % b + for m in ORDER: + t = merged[str(b)].get(m, {}).get("time_s") + r += "%18s" % (("%.3f s" % t) if isinstance(t, (int, float)) else "-") + print(r) +print("\nSDE (identical) per baseline:") +for b in bl: + ss = [merged[str(b)].get(m, {}).get("sde_identical") for m in ORDER] + ss = [s for s in ss if isinstance(s, (int, float))] + print(" %6dd: %.1f–%.1f (spread %.1f%%)" % ( + b, min(ss), max(ss), 100 * (max(ss) - min(ss)) / np.mean(ss))) +print("\nSpeedup cuvarbase-TLS-matched vs GTLS:") +for b in bl: + M = merged[str(b)] + cm = M.get("cuv_tls_matched", {}).get("time_s") + gf = M.get("gtls_full", {}).get("time_s") + gs = M.get("gtls_skip8", {}).get("time_s") + if cm and (gf or gs): + print(" %6dd: vs GTLS-full %-7s vs GTLS-skip8 %-7s" % ( + b, ("%.0fx" % (gf / cm)) if gf else "-", + ("%.0fx" % (gs / cm)) if gs else "-")) diff --git a/scripts/setup-remote.sh b/scripts/setup-remote.sh index d2f9319..5cf2208 100755 --- a/scripts/setup-remote.sh +++ b/scripts/setup-remote.sh @@ -30,10 +30,10 @@ echo "Step 1: Syncing code..." echo "" echo "Step 2: Installing cuvarbase in development mode..." -ssh ${SSH_OPTS} ${SSH_HOST} bash << 'ENDSSH' +ssh ${SSH_OPTS} ${SSH_HOST} REMOTE_DIR="${RUNPOD_REMOTE_DIR:-/workspace/cuvarbase}" bash << 'ENDSSH' set -e -cd /workspace/cuvarbase +cd "${REMOTE_DIR}" # Set up CUDA environment (auto-detect version) if [ -d /usr/local/cuda ]; then diff --git a/scripts/tls_fast_smoke.py b/scripts/tls_fast_smoke.py new file mode 100644 index 0000000..9d978e7 --- /dev/null +++ b/scripts/tls_fast_smoke.py @@ -0,0 +1,177 @@ +"""Smoke + parity test for the fast TLS path (run on a GPU pod). + +Checks, in order: +1. The fast kernels compile. +2. Fast path vs legacy kernel on the same explicit trial grid: + chi2 spectra strongly correlated, same best period, similar SDE. +3. Fast path recovers an injected transit (period + SDE), single LC. +4. Batch of mixed lightcurves: per-LC results match single-LC calls. +5. Large-ndata lightcurve (beyond the legacy 3,500-point cap) works. +""" +import sys +import time +import warnings + +import numpy as np + +warnings.filterwarnings('ignore', message='.*EXPERIMENTAL.*') + +from cuvarbase import tls +from cuvarbase import tls_grids + + +def make_lc(ndata, baseline, period, depth, noise, seed, t0_frac=0.3): + rng = np.random.RandomState(seed) + t = np.sort(rng.uniform(0, baseline, ndata)) + y = 1.0 + rng.randn(ndata) * noise + q = 0.0763 * period ** (-2.0 / 3.0) + t0 = t0_frac * period + rel = np.abs(((t - t0 + 0.5 * period) % period) - 0.5 * period) + y[rel < 0.5 * q * period] -= depth + dy = np.full(ndata, noise) + return t, y, dy + + +def check(name, cond, detail=""): + status = "PASS" if cond else "FAIL" + print("[%s] %s %s" % (status, name, detail)) + if not cond: + check.failures += 1 + + +check.failures = 0 + + +def main(): + # ---------------- 1. compile ---------------- + t_start = time.time() + kernels = tls.compile_tls_fast(block_size=128, nbins=1024) + check("compile", set(kernels) == {'search', 'refine'}, + "(%.1fs)" % (time.time() - t_start)) + + # ---------------- 2. parity vs legacy ---------------- + ndata, baseline = 1200, 27.0 + P_inj, depth = 5.123, 0.01 + t, y, dy = make_lc(ndata, baseline, P_inj, depth, 2e-3, seed=42) + + periods = tls_grids.period_grid_ofir( + t, R_star=1.0, M_star=1.0, oversampling_factor=3, + period_min=1.0, period_max=12.0).astype(np.float64) + _, _, qv = tls_grids.duration_grid_keplerian( + periods, R_star=1.0, M_star=1.0, R_planet=1.0, + qmin_fac=0.5, qmax_fac=2.0, n_durations=15) + qmin, qmax = qv * 0.5, qv * 2.0 + + t0 = time.time() + r_old = tls.tls_search_gpu(t, y, dy, periods=periods, + qmin=qmin, qmax=qmax, n_durations=15, + use_fast=False) + t_old = time.time() - t0 + + t0 = time.time() + r_new = tls.tls_search_gpu(t, y, dy, periods=periods, + qmin=qmin, qmax=qmax, n_durations=15, + use_fast=True) + t_new = time.time() - t0 + + c_old = r_old['chi2'] + c_new = r_new['chi2'] + both = np.isfinite(c_old) & np.isfinite(c_new) + corr = np.corrcoef(c_old[both], c_new[both])[0, 1] + check("parity/chi2-corr", corr > 0.99, "corr=%.5f" % corr) + check("parity/best-period", + abs(r_new['period'] - r_old['period']) / r_old['period'] < 0.01, + "old=%.4f new=%.4f" % (r_old['period'], r_new['period'])) + check("parity/period-hit", + abs(r_new['period'] - P_inj) / P_inj < 0.01, + "P=%.4f (inj %.4f)" % (r_new['period'], P_inj)) + check("parity/SDE", r_new['SDE'] > 0.8 * r_old['SDE'], + "old=%.2f new=%.2f" % (r_old['SDE'], r_new['SDE'])) + check("parity/depth", + abs(r_new['depth'] - depth) / depth < 0.5, + "depth=%.4f" % r_new['depth']) + med_old = np.median(c_old[both]) + med_new = np.median(c_new[both]) + check("parity/chi2-scale", abs(med_new / med_old - 1) < 0.05, + "median old=%.1f new=%.1f" % (med_old, med_new)) + print(" timing: legacy %.3fs, fast %.3fs (%.1fx)" + % (t_old, t_new, t_old / max(t_new, 1e-9))) + + # ---------------- 3. auto-grid recovery ---------------- + res = tls.tls_transit(t, y, dy, R_star=1.0, M_star=1.0, + period_min=1.0, period_max=12.0) + check("auto/period", abs(res['period'] - P_inj) / P_inj < 0.01, + "P=%.4f SDE=%.2f" % (res['period'], res['SDE'])) + check("auto/SDE", res['SDE'] > 5.0, "SDE=%.2f" % res['SDE']) + + # ---------------- 4. batch consistency ---------------- + lcs = [] + P_injs = [3.3, 7.7, 0.0] # third LC = pure noise + for i, P in enumerate(P_injs): + if P > 0: + lcs.append(make_lc(1500 + 400 * i, 27.0, P, 0.012, 2e-3, + seed=100 + i)) + else: + rng = np.random.RandomState(100 + i) + tt = np.sort(rng.uniform(0, 27.0, 1500 + 400 * i)) + lcs.append((tt, 1.0 + rng.randn(len(tt)) * 2e-3, + np.full(len(tt), 2e-3))) + + # shared explicit grid so batch and single calls are comparable + # (auto grids depend on each lightcurve's exact baseline) + tspan_max = max(lc[0].max() - lc[0].min() for lc in lcs) + t_ref = [lc for lc in lcs + if lc[0].max() - lc[0].min() == tspan_max][0][0] + shared_periods = tls_grids.period_grid_ofir( + t_ref, R_star=1.0, M_star=1.0, oversampling_factor=3, + period_min=1.0, period_max=12.0) + + batch = tls.tls_search_batch(lcs, R_star=1.0, M_star=1.0, + periods=shared_periods) + singles = [tls.tls_search_batch([lc], R_star=1.0, M_star=1.0, + periods=shared_periods)[0] + for lc in lcs] + for i, (b, s) in enumerate(zip(batch, singles)): + if P_injs[i] > 0: + # non-deterministic atomics can flip near-tied neighboring + # grid points; allow a few grid steps of slack + check("batch/lc%d-period-match" % i, + abs(b['period'] - s['period']) / s['period'] < 5e-3, + "batch=%.5f single=%.5f" % (b['period'], s['period'])) + check("batch/lc%d-recovered" % i, + abs(b['period'] - P_injs[i]) / P_injs[i] < 0.01, + "P=%.4f SDE=%.2f" % (b['period'], b['SDE'])) + else: + check("batch/lc%d-noise-SDE-consistent" % i, + abs(b['SDE'] - s['SDE']) < 1.5, + "batch=%.2f single=%.2f" % (b['SDE'], s['SDE'])) + sde_noise = batch[2]['SDE'] + sde_sig = batch[0]['SDE'] + check("batch/noise-SDE-lower", sde_noise < sde_sig, + "sig=%.2f noise=%.2f" % (sde_sig, sde_noise)) + + # ---------------- 5. large ndata (legacy cap exceeded) ---------------- + t5, y5, dy5 = make_lc(20000, 27.0, 4.56, 0.008, 2e-3, seed=7) + t0 = time.time() + r5 = tls.tls_search_batch([(t5, y5, dy5)], R_star=1.0, M_star=1.0, + period_min=1.0, period_max=12.0)[0] + dt5 = time.time() - t0 + check("large/period", abs(r5['period'] - 4.56) / 4.56 < 0.01, + "P=%.4f SDE=%.2f (%.2fs)" % (r5['period'], r5['SDE'], dt5)) + + # BJD-scale time offsets + r6 = tls.tls_search_batch([(t5 + 2457000.0, y5, dy5)], + R_star=1.0, M_star=1.0, + period_min=1.0, period_max=12.0)[0] + check("large/bjd-offset", abs(r6['period'] - 4.56) / 4.56 < 0.01, + "P=%.4f SDE=%.2f" % (r6['period'], r6['SDE'])) + + print() + if check.failures: + print("%d FAILURES" % check.failures) + sys.exit(1) + print("ALL SMOKE CHECKS PASSED") + + +if __name__ == '__main__': + main() diff --git a/scripts/tls_fidelity_experiment.py b/scripts/tls_fidelity_experiment.py new file mode 100644 index 0000000..f7c5806 --- /dev/null +++ b/scripts/tls_fidelity_experiment.py @@ -0,0 +1,196 @@ +"""Apples-to-apples fidelity + timing: cuvarbase fast TLS vs reference +transitleastsquares on the SAME light curves and SAME period grid. + +The question is the detection statistic, not just recovery. cuvarbase's +fast path evaluates a COARSE epoch (t0) grid (t0_oversample=3 by +default) plus an exact refinement of the top candidate periods; the +reference steps t0 ~100x finer everywhere. Does coarsening cost SNR? + +To compare cleanly we hold the *statistic* fixed: cuvarbase and the +reference define the SR->SDE transform differently, so we recompute SDE +with cuvarbase.tls_stats on BOTH methods' chi2(period) spectra. The +only thing that then varies is the fidelity of the chi2 spectrum. We +also report a definition-free signal strength, the depth SNR at the +recovered period, sqrt(chi2_null - chi2_min). + +Runs, on identical injected light curves + one shared Ofir grid: + - cuvarbase fast, t0_oversample=3 (default) + - cuvarbase fast, t0_oversample=33 (reference-matched epoch grid) + - reference transitleastsquares + +Usage (GPU pod, batman + transitleastsquares installed): + python scripts/tls_fidelity_experiment.py [--regime tess-ffi] [--nlc 12] +""" +import argparse +import contextlib +import os +import sys +import time +import warnings +from multiprocessing import cpu_count + +warnings.filterwarnings('ignore') + +import numpy as np + +try: # keep our report lines from being clobbered by the C-ext stdout + sys.stdout.reconfigure(line_buffering=True) +except Exception: + pass + +REGIMES = { + 'tess-ffi': dict(ndata=1310, cadence=30. / 60 / 24, noise=1e-3, + pinj=7.7, depth=0.005, pmin=0.6, pmax=13.7), + 'k2': dict(ndata=4320, cadence=30. / 60 / 24, noise=8e-4, + pinj=12.4, depth=0.004, pmin=0.6, pmax=45.), +} + + +def make_lc(c, seed, inject=True): + rng = np.random.RandomState(seed) + t = np.arange(c['ndata']) * c['cadence'] + y = 1.0 + rng.randn(c['ndata']) * c['noise'] + if inject: + q = 0.0763 * c['pinj'] ** (-2.0 / 3.0) + t0 = 0.3 * c['pinj'] + rel = np.abs(((t - t0 + 0.5 * c['pinj']) % c['pinj']) + - 0.5 * c['pinj']) + y[rel < 0.5 * q * c['pinj']] -= c['depth'] + return t, y, np.full(c['ndata'], c['noise']) + + +def recovered(p_found, p_inj, tol=0.01): + for k in (1.0, 2.0, 0.5, 3.0, 1 / 3.0): + if abs(p_found - k * p_inj) / (k * p_inj) < tol: + return True + return False + + +def sde_identical(chi2, periods): + """cuvarbase's SDE, applied to any chi2(period) spectrum, so both + methods are scored by the identical statistic.""" + from cuvarbase import tls_stats + chi2 = np.asarray(chi2, dtype=float) + ok = np.isfinite(chi2) & (chi2 < 1e29) + c = chi2[ok] + best = int(np.argmin(c)) + stats = tls_stats.compute_all_statistics( + c, np.asarray(periods)[ok], best, 0.01, 0.1, 10) + return float(stats['SDE']) + + +def run_cuvarbase(lcs, periods, t0_oversample): + import pycuda.driver as cuda + from cuvarbase.tls import tls_search_batch + from cuvarbase.base import ensure_context + ensure_context() + cuda.Context.synchronize() + t0 = time.perf_counter() + res = tls_search_batch( + lcs, R_star=1.0, M_star=1.0, periods=periods, + t0_oversample=t0_oversample, refine_top_k=50, + return_arrays=True) + cuda.Context.synchronize() + ms = (time.perf_counter() - t0) / len(lcs) * 1000 + rows = [] + for r in res: + if 'error' in r: + rows.append(None); continue + sde_id = sde_identical(r['chi2'], r['periods']) + # depth SNR = sqrt(chi2_null - chi2_min); chi2_null ~ max over grid + cfin = np.asarray(r['chi2'])[np.isfinite(r['chi2'])] + dsnr = float(np.sqrt(max(cfin.max() - r['chi2_min'], 0.0))) + rows.append(dict(period=r['period'], sde_native=r['SDE'], + sde_id=sde_id, dsnr=dsnr)) + return rows, ms + + +def run_reference(lcs, periods): + from transitleastsquares import transitleastsquares + pmin, pmax = float(periods.min()), float(periods.max()) + rows = [] + t_tot = 0.0 + for (t, y, dy) in lcs: + model = transitleastsquares(t, y, dy) + t0 = time.perf_counter() + with open(os.devnull, 'w') as dn, contextlib.redirect_stdout(dn): + r = model.power(R_star=1.0, M_star=1.0, + period_min=pmin, period_max=pmax, + oversampling_factor=3, use_threads=cpu_count(), + show_progress_bar=False) + t_tot += time.perf_counter() - t0 + chi2 = np.asarray(getattr(r, 'chi2')) + pers = np.asarray(getattr(r, 'periods')) + sde_id = sde_identical(chi2, pers) + cmin = float(np.nanmin(chi2)) + dsnr = float(np.sqrt(max(np.nanmax(chi2) - cmin, 0.0))) + rows.append(dict(period=float(r.period), sde_native=float(r.SDE), + sde_id=sde_id, dsnr=dsnr)) + return rows, t_tot / len(lcs) * 1000 + + +def report(tag, rows, ms, p_inj, n_inj): + inj = [r for r in rows[:n_inj] if r] + rec = sum(recovered(r['period'], p_inj) for r in inj) + sid = np.median([r['sde_id'] for r in inj]) + snat = np.median([r['sde_native'] for r in inj]) + dsnr = np.median([r['dsnr'] for r in inj]) + print(" %-38s SDE(identical)=%6.2f SDE(native)=%6.2f " + "depthSNR=%5.2f recov=%d/%d %8.1f ms/LC" + % (tag, sid, snat, dsnr, rec, len(inj), ms)) + return dict(tag=tag, sde_id=sid, sde_native=snat, dsnr=dsnr, + recovered=rec, n=len(inj), ms=ms) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument('--regime', default='tess-ffi', choices=list(REGIMES)) + ap.add_argument('--nlc', type=int, default=12) + ap.add_argument('--depth', type=float, default=None, + help='override injection depth (test marginal signals)') + ap.add_argument('--skip-reference', action='store_true') + args = ap.parse_args() + + from cuvarbase import tls_grids + cfg = dict(REGIMES[args.regime]) + if args.depth is not None: + cfg['depth'] = args.depth + n_inj = args.nlc + lcs = [make_lc(cfg, 5000 + i, inject=True) for i in range(n_inj)] + lcs += [make_lc(cfg, 9000 + i, inject=False) for i in range(3)] + + periods = tls_grids.period_grid_ofir( + lcs[0][0], R_star=1.0, M_star=1.0, oversampling_factor=3, + period_min=cfg['pmin'], period_max=cfg['pmax']) + print("\n=== %s: ndata=%d nperiods=%d P_inj=%.2fd depth=%.4f " + "(%d inj LCs) ===" % (args.regime, cfg['ndata'], len(periods), + cfg['pinj'], cfg['depth'], n_inj)) + print(" SDE(identical) = cuvarbase SDE recomputed on each method's " + "chi2 spectrum;\n depthSNR = sqrt(chi2_null - chi2_min) at " + "the recovered period.\n") + + _ = run_cuvarbase(lcs[:2], periods, 3.0) + _ = run_cuvarbase(lcs[:2], periods, 33.0) + + out = [] + r, ms = run_cuvarbase(lcs, periods, 3.0) + out.append(report("cuvarbase t0os=3 (default)", r, ms, cfg['pinj'], n_inj)) + r, ms = run_cuvarbase(lcs, periods, 33.0) + out.append(report("cuvarbase t0os=33 (matched)", r, ms, cfg['pinj'], n_inj)) + if not args.skip_reference: + r, ms = run_reference(lcs, periods) + out.append(report("reference transitleastsquares", r, ms, cfg['pinj'], n_inj)) + + ref = next((o for o in out if 'reference' in o['tag']), None) + if ref: + print("\n --- vs reference (identical-SDE basis) ---") + for o in out: + if 'cuvarbase' in o['tag']: + print(" %-32s SDE ratio=%.2f depthSNR ratio=%.2f " + "speedup=%.0fx" + % (o['tag'], o['sde_id'] / ref['sde_id'], + o['dsnr'] / ref['dsnr'], ref['ms'] / o['ms'])) + + +if __name__ == '__main__': + main() diff --git a/scripts/tls_kernel_sweep.py b/scripts/tls_kernel_sweep.py new file mode 100644 index 0000000..d6aacfd --- /dev/null +++ b/scripts/tls_kernel_sweep.py @@ -0,0 +1,97 @@ +"""Sweep block_size x nbins for the coarse TLS kernel (kepler-4yr-like +config), reporting steady-state kernel-only times.""" +import warnings +import time + +warnings.filterwarnings('ignore') + +import numpy as np +import pycuda.driver as cuda +import pycuda.gpuarray as gpuarray + +from cuvarbase import tls, tls_grids, tls_models +from cuvarbase.base import ensure_context + +ensure_context() + +ndata, nlc = 65440, 4 +cad = 30. / 60 / 24 +lcs = [] +for i in range(nlc): + rng = np.random.RandomState(1234 + i) + t = np.arange(ndata) * cad + y = 1.0 + rng.randn(ndata) * 6e-4 + lcs.append((t, y, np.full(ndata, 6e-4))) + +periods = tls_grids.period_grid_ofir( + lcs[0][0], R_star=1.0, M_star=1.0, oversampling_factor=3, + period_min=0.6, period_max=500.) +periods32 = np.asarray(periods, np.float32) +_, _, qv = tls_grids.duration_grid_keplerian( + np.asarray(periods, np.float64), R_star=1.0, M_star=1.0, + R_planet=1.0, qmin_fac=0.5, qmax_fac=2.0, n_durations=15) +qmin = (qv * 0.5).astype(np.float32) +qmax = (qv * 2).astype(np.float32) +nperiods = len(periods32) + +t_hi_c, t_lo_c, a_c, b_c, offs, lens, chi2_0, epochs, spans = \ + tls._preprocess_batch(lcs) +T_tab, S1_tab, S2_tab = tls_models.generate_template_tables() +periods_g = gpuarray.to_gpu(periods32) +qmin_g_ = gpuarray.to_gpu(qmin) +qmax_g_ = gpuarray.to_gpu(qmax) +S1_g = gpuarray.to_gpu(S1_tab) +S2_g = gpuarray.to_gpu(S2_tab) +thi_g = gpuarray.to_gpu(t_hi_c) +tlo_g = gpuarray.to_gpu(t_lo_c) +a_g = gpuarray.to_gpu(a_c) +b_g = gpuarray.to_gpu(b_c) +off_g = gpuarray.to_gpu(offs.astype(np.int32)) +len_g = gpuarray.to_gpu(lens.astype(np.int32)) +outn = nlc * nperiods +chi2_g = gpuarray.empty(outn, np.float32) +t0_g = gpuarray.empty(outn, np.float32) +dur_g = gpuarray.empty(outn, np.float32) +dep_g = gpuarray.empty(outn, np.float32) + + +map_g = gpuarray.to_gpu(np.arange(nperiods, dtype=np.int32)) + + +def launch(k, bs, smem): + k['search'](thi_g, tlo_g, a_g, b_g, off_g, len_g, periods_g, + qmin_g_, qmax_g_, map_g, S1_g, S2_g, + np.int32(nperiods), np.int32(nperiods), np.int32(15), + chi2_g, t0_g, dur_g, dep_g, + block=(bs, 1, 1), grid=(nperiods, nlc, 1), shared=smem) + + +ref_chi2 = None +for bs in (128, 256, 512): + for nb in (4096, 8192): + try: + k = tls._get_cached_fast_kernels(bs, nb, 3.0) + smem = tls._tls_fast_shared_size(bs, nb) + launch(k, bs, smem) + cuda.Context.synchronize() + ts = [] + for _ in range(3): + cuda.Context.synchronize() + s = time.perf_counter() + launch(k, bs, smem) + cuda.Context.synchronize() + ts.append(time.perf_counter() - s) + med = sorted(ts)[1] + c = chi2_g.get()[:nperiods] + if ref_chi2 is None: + ref_chi2 = c + corr = 1.0 + else: + ok = (c > 0) & (ref_chi2 > 0) + corr = np.corrcoef(c[ok], ref_chi2[ok])[0, 1] + print("bs=%d nbins=%d smem=%dKB: %.3f s (%.1f ms/LC) " + "scoremax=%.1f corr_vs_first=%.5f" + % (bs, nb, smem // 1024, med, 1000 * med / nlc, + np.nanmax(c), corr)) + except Exception as e: + print("bs=%d nbins=%d FAIL: %r" % (bs, nb, e)) diff --git a/scripts/tls_matched_timing.py b/scripts/tls_matched_timing.py new file mode 100644 index 0000000..72508a5 --- /dev/null +++ b/scripts/tls_matched_timing.py @@ -0,0 +1,78 @@ +"""Matched-fidelity throughput: cuvarbase fast TLS at the default coarse +epoch grid (t0_oversample=3) vs a reference-matched grid (t0_oversample=33) +on the compute-heavy regimes. cuvarbase only, no reference (reference is +>15 min/LC on Kepler). Gives the matched-fidelity ms/LC for the +apples-to-apples GTLS comparison. +""" +import argparse +import time +import warnings + +warnings.filterwarnings('ignore') + +import numpy as np + +REGIMES = { + 'tess-yr': dict(ndata=16850, cadence=30. / 60 / 24, noise=1e-3, + pinj=21.7, depth=0.004, pmin=0.6, pmax=175.), + 'kepler-4yr': dict(ndata=65440, cadence=30. / 60 / 24, noise=6e-4, + pinj=41.3, depth=0.003, pmin=0.6, pmax=500.), +} + + +def make_lc(c, seed): + rng = np.random.RandomState(seed) + t = np.arange(c['ndata']) * c['cadence'] + y = 1.0 + rng.randn(c['ndata']) * c['noise'] + q = 0.0763 * c['pinj'] ** (-2.0 / 3.0) + t0 = 0.3 * c['pinj'] + rel = np.abs(((t - t0 + 0.5 * c['pinj']) % c['pinj']) - 0.5 * c['pinj']) + y[rel < 0.5 * q * c['pinj']] -= c['depth'] + return t, y, np.full(c['ndata'], c['noise']) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument('--nlc', type=int, default=4) + args = ap.parse_args() + + import pycuda.driver as cuda + from cuvarbase.base import ensure_context + from cuvarbase import tls_grids + from cuvarbase.tls import tls_search_batch + ensure_context() + + def timed(lcs, periods, os_): + cuda.Context.synchronize() + t0 = time.perf_counter() + res = tls_search_batch(lcs, R_star=1.0, M_star=1.0, periods=periods, + t0_oversample=os_, refine_top_k=50, + return_arrays=False) + cuda.Context.synchronize() + ms = (time.perf_counter() - t0) / len(lcs) * 1000 + rec = sum(abs(r['period'] - c['pinj']) / c['pinj'] < 0.01 + for r in res if 'error' not in r) + return ms, rec + + print("\n%-12s %8s %10s %10s %8s %s" + % ("regime", "nperiods", "t0os=3 ms", "t0os=33 ms", "factor", + "recov (3/33)")) + print("-" * 74) + for name, c in REGIMES.items(): + globals()['c'] = c + lcs = [make_lc(c, 4000 + i) for i in range(args.nlc)] + periods = tls_grids.period_grid_ofir( + lcs[0][0], R_star=1.0, M_star=1.0, oversampling_factor=3, + period_min=c['pmin'], period_max=c['pmax']) + # warmups (compile both band sets) + timed(lcs[:1], periods, 3.0) + timed(lcs[:1], periods, 33.0) + ms3, r3 = timed(lcs, periods, 3.0) + ms33, r33 = timed(lcs, periods, 33.0) + print("%-12s %8d %10.1f %10.1f %7.1fx %d/%d, %d/%d" + % (name, len(periods), ms3, ms33, ms33 / ms3, + r3, args.nlc, r33, args.nlc)) + + +if __name__ == '__main__': + main() diff --git a/scripts/tls_profile_stages.py b/scripts/tls_profile_stages.py new file mode 100644 index 0000000..48ad47c --- /dev/null +++ b/scripts/tls_profile_stages.py @@ -0,0 +1,204 @@ +"""Stage-level profiling + tuning sweeps for the fast TLS batch engine. + +Times each stage of tls_search_batch separately (by monkeypatching / +re-implementing its flow), then sweeps block_size and nbins on the +kernel-dominated regimes to pick defaults. + +Usage (on pod): + python scripts/tls_profile_stages.py [--regime kepler-4yr] [--nlc 4] +""" +import argparse +import time +import warnings + +warnings.filterwarnings('ignore') + +import numpy as np + + +def make_lcs(regime, nlc): + cfgs = { + 'tess-ffi': dict(ndata=1310, cadence=30. / 60 / 24, noise=1e-3, + pinj=7.7, depth=0.005, pmin=0.6, pmax=13.7), + 'k2': dict(ndata=4320, cadence=30. / 60 / 24, noise=8e-4, + pinj=12.4, depth=0.004, pmin=0.6, pmax=45.), + 'tess-2min': dict(ndata=19710, cadence=2. / 60 / 24, noise=2e-3, + pinj=7.7, depth=0.005, pmin=0.6, pmax=13.7), + 'tess-yr': dict(ndata=16850, cadence=30. / 60 / 24, noise=1e-3, + pinj=21.7, depth=0.004, pmin=0.6, pmax=175.), + 'kepler-4yr': dict(ndata=65440, cadence=30. / 60 / 24, noise=6e-4, + pinj=41.3, depth=0.003, pmin=0.6, pmax=500.), + } + c = cfgs[regime] + lcs = [] + for i in range(nlc): + rng = np.random.RandomState(1234 + i) + t = np.arange(c['ndata']) * c['cadence'] + y = 1.0 + rng.randn(c['ndata']) * c['noise'] + q = 0.0763 * c['pinj'] ** (-2.0 / 3.0) + t0 = 0.3 * c['pinj'] + rel = np.abs(((t - t0 + 0.5 * c['pinj']) % c['pinj']) + - 0.5 * c['pinj']) + y[rel < 0.5 * q * c['pinj']] -= c['depth'] + lcs.append((t, y, np.full(c['ndata'], c['noise']))) + return lcs, c + + +def profile(regime, nlc, block_size=None, nbins=None, refine_top_k=200, + n_durations=15): + import pycuda.driver as cuda + from cuvarbase import tls, tls_grids, tls_models + + lcs, c = make_lcs(regime, nlc) + + def sync(): + cuda.Context.synchronize() + + T = {} + + t0 = time.perf_counter() + periods = tls_grids.period_grid_ofir( + lcs[0][0], R_star=1.0, M_star=1.0, oversampling_factor=3, + period_min=c['pmin'], period_max=c['pmax']) + periods32 = np.asarray(periods, dtype=np.float32) + _, _, qv = tls_grids.duration_grid_keplerian( + np.asarray(periods, np.float64), R_star=1.0, M_star=1.0, + R_planet=1.0, qmin_fac=0.5, qmax_fac=2.0, n_durations=n_durations) + qmin, qmax = (qv * 0.5).astype(np.float32), (qv * 2).astype(np.float32) + T['grid_gen'] = time.perf_counter() - t0 + nperiods = len(periods32) + + bs = block_size or tls._TLS_FAST_DEFAULT_BLOCK + qmin_g = float(qmin.min()) + nb = nbins or tls._auto_nbins(qmin_g, 3.0, bs) + + t0 = time.perf_counter() + kernels = tls._get_cached_fast_kernels(bs, nb, 3.0) + T['compile_or_cache'] = time.perf_counter() - t0 + + t0 = time.perf_counter() + T_tab, S1_tab, S2_tab = tls_models.generate_template_tables() + T['template'] = time.perf_counter() - t0 + + t0 = time.perf_counter() + t_hi_c, t_lo_c, a_c, b_c, offs, lens, chi2_0, epochs, spans = \ + tls._preprocess_batch(lcs) + T['preprocess_cpu'] = time.perf_counter() - t0 + + import pycuda.gpuarray as gpuarray + t0 = time.perf_counter() + periods_gpu = gpuarray.to_gpu(periods32) + qmin_gpu = gpuarray.to_gpu(qmin) + qmax_gpu = gpuarray.to_gpu(qmax) + T_g = gpuarray.to_gpu(T_tab) + S1_g = gpuarray.to_gpu(S1_tab) + S2_g = gpuarray.to_gpu(S2_tab) + thi_g = gpuarray.to_gpu(t_hi_c) + tlo_g = gpuarray.to_gpu(t_lo_c) + a_g = gpuarray.to_gpu(a_c) + b_g = gpuarray.to_gpu(b_c) + off_g = gpuarray.to_gpu(offs.astype(np.int32)) + len_g = gpuarray.to_gpu(lens.astype(np.int32)) + out_n = nlc * nperiods + chi2_g = gpuarray.empty(out_n, np.float32) + t0_g = gpuarray.empty(out_n, np.float32) + dur_g = gpuarray.empty(out_n, np.float32) + depth_g = gpuarray.empty(out_n, np.float32) + sync() + T['h2d_alloc'] = time.perf_counter() - t0 + + smem = tls._tls_fast_shared_size(bs, nb) + map_g = gpuarray.to_gpu(np.arange(nperiods, dtype=np.int32)) + t0 = time.perf_counter() + kernels['search']( + thi_g, tlo_g, a_g, b_g, off_g, len_g, + periods_gpu, qmin_gpu, qmax_gpu, map_g, S1_g, S2_g, + np.int32(nperiods), np.int32(nperiods), np.int32(n_durations), + chi2_g, t0_g, dur_g, depth_g, + block=(bs, 1, 1), grid=(nperiods, nlc, 1), shared=smem) + sync() + T['coarse_kernel'] = time.perf_counter() - t0 + + t0 = time.perf_counter() + chi2_h = chi2_g.get().reshape(nlc, nperiods) + T['d2h_chi2'] = time.perf_counter() - t0 + + K = int(min(refine_top_k, max(16, nperiods // 10), nperiods)) + t0 = time.perf_counter() + cand = np.empty((nlc, K), dtype=np.int32) + for j in range(nlc): + cand[j] = np.argpartition(-chi2_h[j], K)[:K] if K < nperiods \ + else np.arange(nperiods) + cand_g = gpuarray.to_gpu(cand.ravel()) + rchi2_g = gpuarray.empty(nlc * K, np.float32) + rt0_g = gpuarray.empty(nlc * K, np.float32) + rdur_g = gpuarray.empty(nlc * K, np.float32) + rdepth_g = gpuarray.empty(nlc * K, np.float32) + dur_ratio = float(np.median(qmax / qmin)) + dur_span = dur_ratio ** (1.0 / (2.0 * (n_durations - 1))) + t0_hw = min(3.0, max(0.75, 1.5 / (nb * qmin_g))) + kernels['refine']( + thi_g, tlo_g, a_g, b_g, off_g, len_g, + periods_gpu, cand_g, T_g, + np.int32(nperiods), np.int32(K), + np.float32(dur_span), np.float32(t0_hw), np.float32(33.0), + t0_g, dur_g, + rchi2_g, rt0_g, rdur_g, rdepth_g, + block=(bs, 1, 1), grid=(K, nlc, 1), + shared=tls._tls_refine_shared_size(bs)) + sync() + T['refine'] = time.perf_counter() - t0 + + t0 = time.perf_counter() + from cuvarbase import tls_stats + for j in range(nlc): + row = chi2_h[j] + valid = row > 0 + cv = (chi2_0[j] - row[valid].astype(np.float64)) + bi = int(np.argmin(cv)) + tls_stats.compute_all_statistics(cv, periods32[valid], bi, + 0.01, 0.1, 10) + tls_stats.compute_period_uncertainty(periods32[valid], cv, bi) + T['stats_cpu'] = time.perf_counter() - t0 + + total = sum(T.values()) + print("\n%s nlc=%d nperiods=%d ndata=%d bs=%d nbins=%d K=%d" + % (regime, nlc, nperiods, c['ndata'], bs, nb, K)) + for k, v in T.items(): + print(" %-18s %8.3f s (%4.1f%%) %7.2f ms/LC" + % (k, v, 100 * v / total, 1000 * v / nlc)) + print(" %-18s %8.3f s %7.2f ms/LC" + % ('TOTAL', total, 1000 * total / nlc)) + return T + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument('--regime', default='kepler-4yr') + ap.add_argument('--nlc', type=int, default=4) + ap.add_argument('--block-size', type=int, default=None) + ap.add_argument('--nbins', type=int, default=None) + ap.add_argument('--sweep', action='store_true', + help='sweep block_size x nbins on this regime ' + '(reports steady-state coarse-kernel time)') + args = ap.parse_args() + + if args.sweep: + for bs in (64, 128, 256): + for nb in (None, 2048, 4096): + try: + profile(args.regime, args.nlc, block_size=bs, + nbins=nb) + except Exception as exc: + print("bs=%d nbins=%s FAILED: %r" % (bs, nb, exc)) + return + + # steady-state: run twice (first pays compile), report second + profile(args.regime, args.nlc, block_size=args.block_size, + nbins=args.nbins) + profile(args.regime, args.nlc, block_size=args.block_size, + nbins=args.nbins) + + +if __name__ == '__main__': + main()