Metadata-Version: 2.4
Name: imcombiners
Version: 0.1.2
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Rust
Classifier: Topic :: Scientific/Engineering :: Astronomy
Requires-Dist: astro-ndslice>=0.4
Requires-Dist: numpy>=1.24
Requires-Dist: reducers>=0.4.0
Requires-Dist: astropy>=6.1.7 ; extra == 'bench'
Requires-Dist: bottleneck>=1.3 ; extra == 'bench'
Requires-Dist: ccdproc>=2.5.1 ; extra == 'bench'
Requires-Dist: fitsio>=1.2 ; extra == 'bench'
Requires-Dist: pytest>=7 ; extra == 'dev'
Requires-Dist: pytest-benchmark>=4 ; extra == 'dev'
Requires-Dist: matplotlib ; extra == 'dev'
Requires-Dist: ruff ; extra == 'dev'
Requires-Dist: maturin>=1.5,<2 ; extra == 'dev'
Requires-Dist: ipython ; extra == 'dev'
Requires-Dist: jupyter ; extra == 'docs'
Requires-Dist: matplotlib ; extra == 'docs'
Requires-Dist: quartodoc ; extra == 'docs'
Requires-Dist: griffe<1 ; extra == 'docs'
Requires-Dist: pytest>=7 ; extra == 'test'
Requires-Dist: pytest-benchmark>=4 ; extra == 'test'
Requires-Dist: matplotlib ; extra == 'test'
Provides-Extra: bench
Provides-Extra: dev
Provides-Extra: docs
Provides-Extra: test
License-File: LICENSE
Summary: Rust-backed image stack combine + rejection kernels (IRAF imcombine parity)
Home-Page: https://github.com/ysbach/imcombiners
License: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Issues, https://github.com/ysbach/imcombiners/issues
Project-URL: Repository, https://github.com/ysbach/imcombiners

# imcombiners
**(Image + Combiner + Rust(rs))**, made for Python.

<p align="center">
  <img src="logo.png" alt="imcombiners logo" width="170">
</p>


`imcombiners` combines astronomical image stacks with pixel rejection,
normalization, masks, and diagnostics. It supports sigma clipping, a CCD noise
model, and IRAF-style rejection rules. Stack reductions and built-in zero/scale
statistics skip both `NaN` and `inf`.

Documentation: https://ysbach.github.io/imcombiners/
GitHub: https://github.com/ysBach/imcombiners

The Python API supports IRAF `IMCOMBINE` compatibility modes.
Tests and benchmarks compare supported paths against IRAF, Astropy/NumPy,
`ccdproc`, and `bottleneck`. The [image results](https://ysbach.github.io/imcombiners/performance/image-benchmarks.html)
identify their measured inputs, builds, and settings. Use the
[recorded environment and reproduction commands](benchmarks/results/README.md)
when comparing timings.


## First Look
The package has **four** usage modes:

1. Recommended: **Standard `Combiner().combine()`** approach,
2. CLI-friendly: compact `ndcombine()` wrapper,
3. Deep-inspection: **Chained `Combiner()`**, and
4. Advanced: direct kernel calls.

Start with standard `Combiner` usage for ordinary Python workflows.

```python
import numpy as np
import imcombiners as imc

rng = np.random.default_rng(20250311)
stack = rng.normal(1000, 5, (15, 256, 256)).astype("float32")

cmb = imc.Combiner(stack)
out = cmb.combine(
    "median",  # final stack-combination method
    # 1. Optional pre-rejection threshold masking
    thresholds=(0.0, 65000.0),
    # 2. Optional per-image zero/scale normalization
    zero=None,
    scale="median",
    # 3. Optional pixel rejection before final combination
    rejectors=[
        imc.MinMaxClip(n_min=1, n_max=0.1),
        imc.SigClip(sigma=3.0, maxiters=5),
    ],
    diagnostics=None,  # output-only fast path
)
```

See [docs/quarto/index.qmd](docs/quarto/index.qmd#first-look) for the detailed explanations, API-level guidance, and conventions behind this example.

## Features

- Stack combination: mean, median, lower median, percentiles, sum, min, max, variance, and weighted mean via `weight=`.
- 1-D rejection helpers: `imcombiners.kernels` exposes `_1d` functions such as `sigclip_mask_1d`, `pclip_1d`, and `minmax_combine_1d`.
- Pixel rejection: sigma, CCD noise-model, iterative linear, min/max, and IRAF-style percentile clipping. Rejection centers accept mean, median, and lower median (`lmedian`/`lmed`).
- Pipeline helpers: threshold masking, zero/scale normalization, offset padding, masks, `diagnostics=None|"simple"|"full"`, and output-only fast paths.
- See documentations for details and examples.

## Install

For Python projects:
```bash
uv add imcombiners
```
OR
```bash
uv pip install .
```
OR
```bash
uv pip install -e .
```

Source development uses a sibling `../reducers` checkout at version 0.4.x.
Python requires [`reducers>=0.4.0`][package-reducers].

For Rust crate use:

```toml
[dependencies]
imcombiners = { version = "<version>", default-features = false }
```

The `kernel` module is available to Rust consumers without Python or NumPy.
The library crate is named `_core`; for example,
`use _core::kernel::combine::{combine_axis0, CombineKind};`.
Stack-combination kernels expect contiguous C-order arrays shaped `(N, H, W)`.

The default `python` Cargo feature enables the Python bindings. The
`extension-module` feature also enables `python` and is selected automatically
by the Maturin configuration.

To build, test, and inspect the Rust-only dependency graph:

```bash
cargo build --locked --no-default-features
cargo test --locked --no-default-features
cargo tree --locked --no-default-features --target all
```


## Testing and Benchmarks

```bash
uv run --extra test pytest
uv run --extra bench python benchmarks/benchmark_combine.py
uv run --extra bench python benchmarks/benchmark_threads.py
```

For the saved image and IRAF measurements, see the
[result index and reproduction commands](benchmarks/results/README.md).

`--quick` runs the smoke benchmark matrix. Omit it to run the full table that
backs the published benchmark documentation.

The test extra includes Matplotlib for the logo test. To use an already active
development environment, run `uv run --active --no-sync pytest` after installing
the test dependencies. Set `IMC_PERF_TEST=1` to enable the performance checks.
Benchmark environment tables report the compiled Rust `reducers` version and
source separately from the installed Python distribution. Missing provenance
is reported as `unknown`; an unavailable extension reports `unavailable`.

For version tags and automated PyPI/crates.io publishing, see
[the release procedure](https://github.com/ysBach/imcombiners/blob/main/RELEASING.md).

## Building documentation

```bash
make docs-build       # Regenerate API pages and render the website.
make docs-tutorials   # Execute and render only the tutorials.
```

For an existing environment with documentation dependencies installed, set
`DOCS_PYTHON`, for example
`make docs-build DOCS_PYTHON="uv run --active --no-sync --offline python"`.

[package-reducers]: https://github.com/ysbach/reducers

