# CASCADE-nu

`CASCADE-nu` is a pip-installable CASCADE predictor package with:
- batched `13C` and `1H` prediction
- prediction from precomputed geometries (no re-embedding)
- shift matching utilities with `dp` (default), `scipy`, and `murty` (k-best)

Bundled defaults:
- 13C model: `20260312_13c_joint_component_from_assigned_normboth`
- 1H model: `20260312_1h_joint_component_from_assigned_normboth`

## Install

```bash
pip install CASCADE-nu
```

## Prediction CLI

### From SMILES

```bash
cascade-nu --smiles "CCO" --nucleus 1H
cascade-nu --smiles-file smiles.txt --nucleus 13C --batch-size 64
```

### From precomputed geometries (parquet structures dataset)

Input dataset requirements:
- required columns: `smiles`, `molblock`
- optional columns: `conformer_rank`, `conformer_id`, `energy`, `energy_method`

Predict only rank-0 conformers:

```bash
cascade-nu \
  --structures-path /path/to/structures.parquet \
  --conformer-rank 0 \
  --nucleus 1H \
  --batch-size 64
```

Predict using all conformers in the dataset:

```bash
cascade-nu \
  --structures-path /path/to/structures.parquet \
  --use-all-conformers \
  --nucleus 13C
```

## Prediction Python API

```python
from cascade_x import predict_smiles, predict_structures, predict_sdf

# Standard SMILES mode
res = predict_smiles(["CCO", "c1ccccc1"], nucleus="1H", batch_size=32)
print(res.predictions.head())

# Precomputed-geometry parquet mode
res2 = predict_structures(
    "/path/to/structures.parquet",
    nucleus="1H",
    conformer_rank=0,
    use_all_conformers=False,
)

# Precomputed-geometry SDF mode
res3 = predict_sdf("/path/to/embedded.sdf", nucleus="13C")
```

## Matching CLI

`cascade-nu-match` expects one shift per line in each file.

### Default fast path (`dp`)

```bash
cascade-nu-match \
  --predicted-file predicted.txt \
  --experimental-file experimental.txt \
  --solver dp
```

### SciPy Hungarian option

```bash
cascade-nu-match \
  --predicted-file predicted.txt \
  --experimental-file experimental.txt \
  --solver scipy
```

### Murty k-best option

```bash
cascade-nu-match \
  --predicted-file predicted.txt \
  --experimental-file experimental.txt \
  --solver murty \
  --k-best 25 \
  --temperature 0.5 \
  --mae-delta-threshold 0.2
```

## Matching Python API

```python
from cascade_x import match_shifts

pred = [7.35, 7.30, 1.25]
exp = [7.34, 7.31, 1.20]

# DP (default)
r1 = match_shifts(pred, exp, solver="dp")

# SciPy Hungarian
r2 = match_shifts(pred, exp, solver="scipy")

# Murty k-best
r3 = match_shifts(pred, exp, solver="murty", k_best=10)
print(r3.assignment_entropy, r3.num_competing_assignments)
```

## Solver Notes

- `dp` is the default and is intended for the standard 1D shift objective.
- `scipy` uses Hungarian assignment on the full padded cost matrix.
- `murty` is the k-best solver; use this when you need assignment ambiguity analysis.
- `dp` and `scipy` are top-1 only (`k_best` must be `1`).

## Output Notes

- Prediction failures are returned explicitly (`failures`) with reason tags.
- Prediction output always includes `nucleus` and `model_id`.
- For structures-mode predictions, conformer metadata columns are propagated when available.
