Metadata-Version: 2.4
Name: navette
Version: 0.6.32
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Intended Audience :: Science/Research
Requires-Dist: numpy>=2.0
Requires-Dist: scipy>=1.13.0
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: numba>=0.61.0 ; extra == 'all'
Requires-Dist: pytest ; extra == 'all'
Requires-Dist: maturin>=1.5,<2.0 ; extra == 'all'
Requires-Dist: pytest ; extra == 'dev'
Requires-Dist: maturin>=1.5,<2.0 ; extra == 'dev'
Requires-Dist: numba>=0.61.0 ; extra == 'numba'
Provides-Extra: all
Provides-Extra: dev
Provides-Extra: numba
License-File: COPYING
License-File: COPYING.LESSER
Summary: A high-performance optical engine utilizing a Scattering Matrix algorithm for stable simulation of light in stratified media.
Author-email: opticsWolf <opticswolf@protonmail.com>
License-Expression: LGPL-3.0-or-later
Requires-Python: >=3.12
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/opticsWolf/Navette

# Navette - Weaving thin-film systems that perform

[![crates.io](https://img.shields.io/crates/v/navette?logo=rust&label=crates.io)](https://crates.io/crates/navette)
[![PyPI](https://img.shields.io/pypi/v/navette?logo=pypi&logoColor=white&label=PyPI)](https://pypi.org/project/navette/)
[![Rust 1.88+](https://img.shields.io/badge/rust-1.88%2B-orange?logo=rust)](rust/navette/Cargo.toml)
[![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue?logo=python&logoColor=white)](pyproject.toml)
[![License: LGPL-3.0-or-later](https://img.shields.io/badge/license-LGPL--3.0--or--later-blue)](COPYING.LESSER)
[![CI](https://github.com/opticsWolf/Navette/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/opticsWolf/Navette/actions/workflows/ci.yml)

**Navette** is a high-performance, physically rigorous 1D optical engine designed for the simulation of light propagation in stratified media. Built on a modern **Scattering Matrix (S-matrix)** architecture, it offers a numerically stable and vectorized alternative to traditional Transfer Matrix Methods (TMM).

### 1. Unconditional Numerical Stability

Traditional TMM suffers from numerical divergence (exponentially growing evanescent waves) when dealing with thick layers or highly absorbing materials. Navette utilizes the **Redheffer Star Product** to propagate scattering matrices, ensuring that all matrix elements remain bounded and physically meaningful, regardless of layer thickness.

### 2. High-Concurrency Performance

As a Principal Performance Engineer, you need tools that scale. Navette is built for speed:

- **Parallel Execution**: Utilizes Rust + rayon data-parallelism across wavelengths/angles to saturate all available CPU cores.
    
- **Vectorized Engine**: Operations are performed across the entire (wavelength × angle) coordinate space in a single pass, eliminating Python's loop overhead.
    
- **Memory Efficiency**: Collapses multi-layer stacks into a compact global S-matrix to minimize cache misses.
    

**Measured, not claimed.** All numbers below are `--release` builds on a
32-core Windows box, taken by the scripts named beside them under
`validation/benches/`; each of those scripts refuses to run against a `debug`
build (see the profile note under *Getting started*). "vs numba" compares
against the numba reference implementation this engine replaced.

| What | Measured | Script |
|---|---|---|
| Full observable mask, 40 lambda x 3 theta, 5 layers (complex amplitudes + dispersion) | **0.164 ms** median -- ~1.4 us per point for *every* channel | `bench_backside_speed` |
| Rigorous 12-channel request, 6 layers, 20 000 / 60 000 points | **1.68 ms / 4.02 ms**, i.e. **1.1-1.8x the numba kernel** | `bench_core_engine_scaling.py` |
| Photometric 4-channel request, same grid sizes | **1.50 ms / 3.70 ms** | `bench_core_engine_scaling.py` |
| pchip interpolation, 1 M points | **1.22 ms** (1.2 ns/pt) vs 1.59 ms numba; accuracy identical (~1e-14 vs analytic) on both sides | `1dinterpol_test_bench` |
| dE76 / dE94 / CMC / DIN99 / dE2000 batches | **23-36x faster** than the reference, at exact parity with `colour-science` including black/white/near-black rows | `bench_validate_color` |
| Weaver `set_data` / `get_weaved` / `unweave_cached` | **1.5-7.8x** the Python reference across small and mid grids | `navette_spectral_bench` |
| Batch `unweave_collection` | **1.15-2.29x** faster than before R5.1; still the one path that can trail the reference at extreme key counts | `navette_spectral_bench` |
| One LM thickness optimize (synthesis), with needle re-fold | **2.1 ms**, re-fold **9.1 %** overhead | `bench_refold` |
| Structure grid assert | **0.9 us** | `bench_grid_assert` |

Two caveats kept deliberately visible: small grids (under ~2 000 points) are
dispatch-bound and still behind the numba kernel, and `bench_refold` does not
exercise the needle *insertion* path, which is the expensive part of synthesis.

### 3. Partial Coherence Support

Real-world systems often involve thick substrates (like a 1mm glass slide) where phase information is lost. Navette features a **Hybrid Coherence Engine**:

- **Coherent Blocks**: Preserves phase for thin-film interference.
    
- **Incoherent Interfaces**: Switches to intensity-based propagation for thick layers, preventing the "unphysical ringing" caused by assuming perfect coherence across a macroscopic substrate.
    

### 4. Advanced Physics Modeling

Navette goes beyond simple Fresnel equations to provide research-grade accuracy:

- **Interface Roughness**: Implements the **Névot-Croce** model, providing superior accuracy for high-frequency or X-ray reflectometry compared to standard Gaussian approximations.
    
- **Ellipsometric Rigor**: Outputs (Ψ,Δ) parameters that strictly follow the **Azzam & Bashara** convention, ensuring direct compatibility with commercial ellipsometers (e.g., Woollam, Horiba).

### 5. Automated Coating Design

Navette doesn't just simulate — it synthesizes, with the classic **needle method** running natively on the same engine:

- **Needle Insertion**: Probes every candidate position with an infinitesimal test layer and inserts real material where the merit function improves most — the Tikhonravov needle algorithm, merit-driven and target-aware.

- **Thickness Optimization**: Levenberg-Marquardt refinement over free layers with bounds and clamping, interleaved with insertion passes and impact-ranked cleanup (merge, thin-layer removal, re-optimization).

- **Multi-domain Targets**: One joint merit over spectral, angular, and CIE color demands — multiple angles, illuminants with own-white metamerism control, and per-target wavelength windows — all folded into the needle gradient with analytic chain-rule terms, so a single run designs for daylight and showroom light at once.

- **Graded Media**: Gradient-index profiles expand natively for simulation and serve as pinned background (substrate diffusion gradients, rugate foundations) while the needle designs around them.
### Technical Specifications

|**Feature**|**Implementation & Engineering Benefit**|
|---|---|
|**Core Algorithm**|**1D Scattering Matrix ($S$-matrix)**: Utilizes the Redheffer Star Product to eliminate numerical divergence and precision loss in thick or highly absorbing layers.|
|**Propagation Logic**|**Hybrid Mixed Coherence**: Sophisticated dual-stage engine supporting phase-accurate (coherent) and intensity-only (incoherent) layers within a single pass.|
|**Coherent Blocks**|**$2 \times 2$ Complex Field Matrices**: Maintains full phase and amplitude information, ensuring rigorous calculation of thin-film interference and ellipsometric parameters.|
|**Incoherent Blocks**|**Stokes-Mueller / Intensity Redheffer**: Prevents unphysical interference artifacts in macroscopic substrates by utilizing intensity-based propagation.|
|**Roughness Model**|**Névot-Croce (Exact Wavevector)**: Achieves research-grade accuracy for X-ray and UV interfaces by modeling exact wavevector correlations across boundaries.|
|**Optimization**|**Rust / rayon + PyO3**: Native multi-threaded kernels (GIL released) with a thin Python API, optimized for high-concurrency simulation and real-time GUI responsiveness.|
|**Polarization**|**Full $s$ and $p$ Support**: Comprehensive Jones and Stokes calculus integration, following standard commercial ellipsometry conventions (Azzam & Bashara).|
|**Complexity**|**$O(N)$ Scaling**: Optimized linear time complexity relative to the number of layers, ensuring stable performance for complex multi-stack architectures.|

### Project layout

```
Navette/
├── Cargo.toml                # Rust workspace (cargo check/test --workspace)
├── pyproject.toml            # maturin project: builds the `navette` wheel (src layout)
├── src/navette/              # unified Python package
│   ├── __init__.py           # version + public surface
│   ├── color/                # wrapper over native `navette._color`
│   ├── interpolate/          # wrapper over native `navette._interpolate`
│   ├── smatrix/              # ScatterMatrix + needle (native `navette._smatrix`)
│   ├── spectralweave/        # weavers + merit (native `navette._spectralweave`)
│   ├── materials/            # dispersion models (native `navette._materials`)
│   ├── _*.py                 # shims re-exporting the `navette._navette` submodules
│   ├── structure/            # stacks, architect (native model + thin wrappers)
│   ├── synthesis/            # needle pipeline driver (native DesignStack)
│   ├── config/               # native-validated holders, program documents
│   └── data/CIE/             # bundled reference spectra
├── rust/                     # Rust sources: one engine crate + bindings
│   ├── navette/              # pure-Rust engine (color/interpolate/materials/
│   │                         # smatrix/spectralweave/structure modules;
│   │                         # published as `navette` on crates.io)
│   └── navette-py/           # PyO3 aggregator -> navette._navette (one wheel)
├── validation/               # tests, parity, benches, goldens + references (see validation/README.md)
├── tools/check_exposure.py   # bidirectional exposure lint (CI)
├── examples/  docs/plans/  benchmarks/
```

### Install & build

```powershell
# Single aggregated native extension (navette._navette, all engines):
maturin develop --release
# checks
cargo check --workspace
cargo test --workspace     # everything (needs Python for binding crates)
cargo test-pure            # pure-Rust gate (no Python needed)
cargo fmt --all            # rustfmt defaults; CI fails on any diff
python tools/check_toolchain.py   # is your clippy as new as CI's?
pytest validation
```

> **Lint on the toolchain CI uses.** `cargo clippy` only reports the lints its
> own version knows. Between 0.6.13 and 0.6.30 the local toolchain was one
> minor version behind CI's `stable`, the local run was clean, and CI was red
> for 17 consecutive pushes on a lint the local clippy did not have.
> `tools/check_toolchain.py` fails when that gap reopens.

Run this once per clone so `git blame` skips the tree-wide reformat commit
(0.6.32) and points at whoever actually wrote each line:

```powershell
git config blame.ignoreRevsFile .git-blame-ignore-revs
```

> **Always pass `--release`.** Plain `maturin develop` builds with the `dev`
> profile: the extension imports and computes correctly, but runs several
> times slower, so every timing taken against it is meaningless. This is not
> hypothetical — a whole round of committed benchmark results (and the
> conclusions drawn from them) had to be discarded for exactly this reason.
> `navette.build_profile()` reports which profile is installed, and the
> benches under `validation/benches/` exit rather than time a `"debug"` one.

### Architecture: Rust core, Python addon

All logic and all validation live in the `navette` Rust crate — it runs
fully standalone (file → design → solve → report, no interpreter).
The Python package is a thin addon: validated config holders, YAML→dict
parsing, result reshapes, and re-exports. Conversely every feature-level
Rust function is exposed via PyO3, so Python can drive the whole engine.
`tools/check_exposure.py` enforces this both ways in CI (see
docs/plans/exposure_audit.md).

### CI

`.github/workflows/ci.yml` runs on every push and pull request:
`cargo test --workspace`, a zero-compiler-warnings check (`-D warnings`),
`pytest validation` on Windows and Linux, the exposure and CIE-sync lints,
and an assertion that the installed extension is a release build.
`cargo clippy -D warnings` (since 0.6.6) and `cargo fmt --all --check`
(since 0.6.32) are blocking; nothing in the workflow is advisory any more.

### Layout notes

- `rust/` holds the Cargo workspace (the single `navette` engine crate
  plus the `navette-py` PyO3 aggregator) — the idiomatic Rust layout,
  publishable to crates.io.
- `src/navette/` is the Python package in src-layout — the idiomatic
  Python layout, which maturin detects automatically for mixed projects.

### Release & publish

Release automation: tag `vX.Y.Z` (must match `pyproject.toml`, workspace
`Cargo.toml`, its internal `navette` dependency, `__about__.py` and both
`Cargo.lock` entries — all six enforced by CI) →
`.github/workflows/release.yml`
builds wheels (Linux/Windows/macOS) and publishes to PyPI (trusted
publisher) + crates.io (token), leaf crates first.

```powershell
maturin build --release   # -> target/wheels/navette-0.6.32-*.whl (single wheel, all engines)
```

#### Optimizer backends

`LmConfig(optimizer=...)` chooses which least-squares solver runs.
`navette._smatrix.available_optimizers()` reports what the installed wheel
actually has; a name it lacks is refused with the rebuild command, never
quietly replaced by a different solver.

| Name | What it is |
|---|---|
| `"builtin"` (default) | This crate's bounded Levenberg-Marquardt: QR step solve, gain-ratio damping, analytic Jacobian. Bounds are enforced by vetoing and clamping the solved step, so a thickness **may finish exactly on a bound** — which is how the synthesis loop learns a film wants removing. |
| `"trf"` | Trust-region reflective (Branch-Coleman-Li), the reference method for *bounded* least squares and the same algorithm as `scipy.optimize.least_squares(method="trf")`. Hand-rolled, no dependency, always available. Bounds enter the subproblem rather than clipping its answer, so a boundary optimum is handled by construction — but its iterates are strictly interior, so it stops one ULP short of a bound instead of on it. `lambda_*` and `damping` do nothing here. |

#### Optional cargo features

Off by default, so a standard wheel pulls no extra dependencies.

| Feature | What it adds |
|---|---|
| `opt-minpack-lm` | `LmConfig(optimizer="minpack_lm")` — the `levenberg-marquardt` crate (MINPACK `lmdif`-derived, MIT), as a reference to compare the built-in LM against. Unbounded, so it runs on an interior reparametrization: its optima are strictly inside the thickness box, where the built-in's may sit exactly on it. |
| `opt-argmin` | `LmConfig(optimizer="argmin_gauss_newton")` and `"argmin_trust_region"` — two solvers from the argmin ecosystem (MIT/Apache-2.0), as **baselines**, not as candidates. Both unbounded. The Gauss-Newton one is undamped, so it raises as soon as `JᵀJ` is singular — a film driven toward zero thickness is enough — and it refuses two of the three refold starts in `validation/review/lm_check.py`. The trust region finds the right optimum but has no convergence test of its own, so it always runs the full `max_iterations`: 218–393 residual evaluations where `"trf"` takes 8–32. Shares `nalgebra` with `opt-minpack-lm`. |

```powershell
maturin develop --release --features opt-minpack-lm
maturin develop --release --features opt-argmin
```

Manual fallback: `cargo publish -p navette`;
`maturin upload target/wheels/navette-0.5.0-*.whl`.

