Metadata-Version: 2.4
Name: aethra
Version: 0.1.0
Summary: A configurable pipeline for detecting microlensing events in photometric light curves.
Author-email: YOUR NAME <you@example.com>
License: MIT License
        
        Copyright (c) 2026 YOUR NAME
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/rges-pit/aethra
Project-URL: Repository, https://github.com/rges-pit/aethra
Project-URL: Issues, https://github.com/rges-pit/aethra/issues
Keywords: astronomy,microlensing,photometry,light-curves,time-series,exoplanets
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Astronomy
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.21
Requires-Dist: pandas>=1.3
Requires-Dist: scipy>=1.7
Requires-Dist: astropy>=5.0
Requires-Dist: pyyaml>=6.0
Provides-Extra: parquet
Requires-Dist: pyarrow>=7.0; extra == "parquet"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: ruff>=0.1; extra == "dev"
Dynamic: license-file

# aethra

A configurable pipeline for detecting **microlensing events** in photometric
light curves. It works with any dataset that has time, magnitude, and
magnitude-error columns (column names are configurable), automatically handling
file-format detection, multi-object grouping, observing-season splitting, and
multi-band ("achromatic") vetoes.

## What it does

For each object the pipeline:

1. Splits the light curve into observing **seasons** (by time gaps).
2. Scans each season for a brightening **bump** (rolling weighted-flux SNR) and
   checks the curve is **non-flat** (reduced χ² + consecutive outliers).
3. Applies three **vetoes** to reject variable stars:
   - **periodic** — significant Lomb–Scargle periodicity in off-event seasons,
   - **recurrent** — a comparable bump repeating in other seasons,
   - **chromatic** — the brightening disagrees across photometric bands.
4. Fits a **point-source point-lens (PSPL)** model to surviving candidates and
   flags short-timescale **free-floating-planet (FFP)** candidates.

The result is a tidy `pandas.DataFrame`, one row per object, with the columns
listed in [`OUTPUT_COLUMNS`](src/aethra/schema.py).

## Installation
for the most updated version:

```bash
git clone https://github.com/rges-pit/aethra.git
cd aethra
pip install -e .
```
(Note: don't forget the . after the -e)

or stable version: 

```
pip install aethra
```
Reading Parquet input needs the optional extra:

```bash
pip install -e ".[parquet]"
```

For development (tests + linting):

```bash
pip install -e ".[dev]"
```

Requires Python ≥ 3.9. Core dependencies: NumPy, pandas, SciPy, Astropy.

## Quick start

```python
from aethra import load_and_run

config = {
    "time_col": "bjd",
    "mag_col":  "mag",
    "err_col":  "mag_err",
    "group_col": "name",   # column identifying each object in the table
}

results = load_and_run("data.parquet", config)
candidates = results[results["is_candidate"]]
```

`load_and_run` auto-dispatches on the input type:

| `input_path`                                | Interpreted as |
|---------------------------------------------|----------------|
| `pd.DataFrame`                              | One table; objects split by `group_col` |
| `"data.parquet"` / `.fits` / `.csv` / `.txt`| One table file |
| `"lc/*.txt"` (glob)                         | One light curve per matched file |
| `("lc/*_W149.txt", "lc/*_Z087.txt")`        | Paired per-filter files matched by filename stem |

You can also call the per-DataFrame driver directly:

```python
from aethra import run_pipeline_from_dataframe
results = run_pipeline_from_dataframe(df, config)
```

## Configuration from a YAML file

Rather than writing the `config` dict inline, you can keep all settings in a
YAML file and version it alongside your results — so every run records exactly
how it was configured. See [`examples/config.yaml`](examples/config.yaml) for a
fully commented template.

```python
from aethra import load_config, load_and_run

config = load_config("config.yaml")
results = load_and_run("data.parquet", config)
```

Keys you omit fall back to the built-in defaults; YAML `null` maps to Python
`None` (e.g. `group_col: null` means one object per file).

## Command line

The package installs an `aethra` console script:

```bash
# Drive the whole run from a YAML config file
aethra data.parquet --config config.yaml -o results.csv

# Or pass options as flags (flags override anything also set in --config)
aethra "lc/*.txt" --columns bjd mag mag_err -o results.csv

# A multi-object CSV with a header row
aethra data.csv --sep "," --header 0 --group-col name -o results.csv
```

Run `aethra --help` for the full option list.

## Configuration reference

Passed as the `config` dict (or the matching CLI flag).

### Required

| Key        | Meaning                          |
|------------|----------------------------------|
| `time_col` | Time column (e.g. BJD)           |
| `mag_col`  | Magnitude column                 |
| `err_col`  | Magnitude-uncertainty column     |

### Grouping & input parsing

| Key        | Default | Meaning |
|------------|---------|---------|
| `group_col`| `None`  | Column whose unique values identify each source. `None` = one object per file/DataFrame. |
| `sep`      | `r"\s+"`| Separator regex for text files (`","` for CSV). |
| `header`   | `None`  | Header row index for text files; `None` = no header. |
| `columns`  | `None`  | Column names to assign when there is no header row. |

### Filters / achromatic test

| Key                | Default        | Meaning |
|--------------------|----------------|---------|
| `filter_col`       | `None`         | Band column. `None` skips the achromatic test. |
| `target_filter`    | `"F146"`       | Band used for event detection. |
| `primary_filter`   | `"F146"`       | Primary band in the achromatic test. |
| `secondary_filters`| `None`         | One band (str) or several (list) to compare against. |

### Tuning

| Key                   | Default | Meaning |
|-----------------------|---------|---------|
| `min_points`          | `10`    | Minimum points per season to analyze. |
| `season_gap_days`     | `100`   | Day gap that separates observing seasons. |
| `ffp_tE_max`          | `2.0`   | Max tE (days) to flag a free-floating-planet candidate. |
| `good_pspl_chi2`      | `2.5`   | Reduced-χ² threshold for an acceptable PSPL fit. |
| `chromatic_min_points`| `5`     | Min points per band for the achromatic test. |
| `fap_threshold`       | `0.01`  | False-alarm threshold for periodicity. **See Known quirks.** |

## Output columns

`name`, `is_candidate`, `is_ffp_candidate`, `is_variable_star`,
`veto_periodic`, `veto_recurrent`, `veto_chromatic`, `is_achromatic`,
`best_season`, `is_flat`, `chi2_flat`, `dof_flat`, `chi2_red_flat`,
`bump_flag`, `bump_snr`, `t0_fit`, `u0_fit`, `tE_fit`, `chi2_red_pspl`,
`baseline_mag`, `peak_mag`.

`t0_fit` is reported with `2450000` subtracted.

## Package layout

```
src/aethra/
├── __init__.py      # public API
├── schema.py        # OUTPUT_COLUMNS
├── config.py        # load_config (YAML → config dict)
├── detection.py     # outlier / flatness / bump detection + recurrent veto
├── variability.py   # non-flatness + Lomb–Scargle periodicity veto
├── achromatic.py    # multi-band achromaticity test
├── pspl.py          # PSPL magnification model + fitting
├── seasons.py       # season splitting and per-season scan
├── pipeline.py      # run_pipeline_from_dataframe (main driver)
├── io.py            # file loaders + load_and_run dispatcher
└── cli.py           # `aethra` console script
```

## Known quirks

These reflect the behavior of the original code and are **preserved as-is**;
they are documented here so you can decide whether to change them:

- **`config["fap_threshold"]` is not currently wired into the periodic veto.**
  `run_pipeline_from_dataframe` calls the off-season periodicity check with a
  hardcoded `fap_threshold=1e-6`. The config key only affects the standalone
  `is_periodic` / `lomb_scargle_test` helpers. To honor the config value in the
  pipeline, pass `fap_threshold=...` into `periodic_veto_from_other_seasons`.
- **`split_into_seasons` labels the very first data point separately.** The
  first point of a light curve keeps label `0` while the rest of season one is
  labeled `1`. In practice that single-point "season 0" is dropped by the
  `min_points` filter, but it does mean the first epoch is excluded from the
  season scan.

## Testing

```bash
pip install -e ".[dev]"
pytest
```

## License

MIT — see [LICENSE](LICENSE).
