# API documentation

This document describes the public API of the `mass-decomposition` crate.

## Table of contents

- [Mass tolerance](#mass-tolerance)
- [Core configuration](#core-configuration)
- [Input types](#input-types)
- [Decomposition functions](#decomposition-functions)
- [Result types](#result-types)
- [Feature vectors](#feature-vectors)
- [Spectrum decomposer](#spectrum-decomposer)
- [Errors](#errors)

## Mass tolerance

```rust
pub enum MassTolerance {
    Dalton(f64),
    Ppm(f64),
}
```

`MassTolerance` is the canonical way to supply a mass tolerance. The two
variants are mutually exclusive, so callers must choose exactly one unit.

- `MassTolerance::Dalton(da)` — absolute mass window in Daltons.
- `MassTolerance::Ppm(ppm)` — relative mass window in parts per million.

### `MassTolerance::to_ppm`

```rust
pub fn to_ppm(self, target_mass: f64) -> f64
```

Converts the tolerance to ppm for a given target mass, applying the 200 Da rule:
the reference mass is `max(target_mass, 200.0)`. See the [README](README.md) for
why this rule is used.

## Core configuration

### `DecompositionConfig`

```rust
pub struct DecompositionConfig {
    pub mass_tolerance: MassTolerance,
    pub allowed_elements: Vec<Element>,
    pub max_element_counts: Option<Composition>,
    pub min_dbe: f64,
    pub max_dbe: f64,
    pub candidate_limit: usize,
    pub allow_half_integer: bool,
    pub isotopic_pattern_params: Option<IsotopicPatternParams>,
}
```

Configuration for a single decomposition run.

| Field | Description |
|-------|-------------|
| `mass_tolerance` | Mass window as `MassTolerance`. |
| `allowed_elements` | Element symbols that may appear in candidates (e.g. `vec!["H", "C", "N", "O"]`). |
| `max_element_counts` | Optional per-element maxima. `None` uses the crate defaults. |
| `min_dbe` / `max_dbe` | Inclusive double-bond equivalent bounds. |
| `candidate_limit` | Maximum number of candidates returned per mass. |
| `allow_half_integer` | If `true`, DBE values like `0.5` are accepted (radical ions). |
| `isotopic_pattern_params` | Optional parameters for isotope-aware scoring/filtering. |

### `DecompositionConfig::default_lcms_positive`

```rust
pub fn default_lcms_positive() -> Self
```

Sensible defaults for positive-ESI LC-MS/MS of small molecules:

- tolerance: `MassTolerance::Dalton(0.01)`,
- elements: H, C, N, O, P, S,
- DBE range: `0.0` to `40.0`,
- candidate limit: `1`,
- half-integer DBE: `false`.

## Input types

### `PrecursorInfo`

```rust
pub struct PrecursorInfo {
    pub monoisotopic_mass: f64,
    pub charge: i32,
    pub adduct: Option<String>,
    pub isotopic_pattern: Option<IsotopicPattern>,
}
```

Describes the ion to decompose. `charge` must be `+1` or `-1`. `adduct` is
metadata and does not affect decomposition. If `isotopic_pattern` is supplied
and `isotopic_pattern_params` is set in `DecompositionConfig`, the crate uses
the pattern to constrain C / S / Cl / Br counts and to add an isotope-agreement
bonus to the score.

### `IsotopicPattern`

```rust
pub struct IsotopicPattern {
    pub peaks: Vec<(f64, f64)>,
}
```

A list of `(m/z, intensity)` peaks. Only the first two peaks (M+0 and M+1) are
used by the current scorer.

### `FragmentPeak`

```rust
pub struct FragmentPeak {
    pub mz: f64,
    pub intensity: f64,
}
```

A single fragment peak. `intensity` is used by the spectrum normalizer as a
weight during mass-error linear regression.

## Decomposition functions

### `decompose_precursor`

```rust
pub fn decompose_precursor(
    precursor: &PrecursorInfo,
    config: &DecompositionConfig,
) -> Result<Vec<(MolecularFormula, f64)>, DecompositionError>
```

Decompose a single precursor mass. Returns candidates sorted by score
descending, each paired with its mass error in ppm. Returns
`DecompositionError::NoCandidate` if no formula satisfies the constraints.

### `decompose_fragments`

```rust
pub fn decompose_fragments(
    precursor: &MolecularFormula,
    fragments: &[FragmentPeak],
    config: &DecompositionConfig,
) -> Result<Vec<FragmentFormulaResult>, DecompositionError>
```

Decompose each fragment peak, constraining each element count to be no larger
than the precursor's count for that element.

### `decompose_fragment_batch`

```rust
pub fn decompose_fragment_batch(
    precursor: &MolecularFormula,
    fragments: &[FragmentPeak],
    config: &DecompositionConfig,
) -> Result<Vec<FragmentFormulaResult>, DecompositionError>
```

Same semantics as `decompose_fragments`, but processes fragments in parallel
with `rayon`. Result order matches input order.

## Result types

### `MolecularFormula`

```rust
pub struct MolecularFormula {
    pub composition: Composition,
    pub monoisotopic_mass: f64,
    pub nominal_mass: u32,
    pub dbe: f64,
    pub mass_defect: f64,
    pub is_valid_valence: bool,
}
```

A decomposed formula with derived properties.

### `FragmentFormulaResult`

```rust
pub struct FragmentFormulaResult {
    pub peak: FragmentPeak,
    pub candidates: Vec<(MolecularFormula, f64)>,
}
```

Result for one fragment peak. `candidates` is sorted by score descending and
truncated to `config.candidate_limit`.

### `Composition`

```rust
pub struct Composition {
    pub counts: HashMap<Element, u32>,
}
```

User-facing formula representation mapping element symbols to counts.

## Feature vectors

### `FormulaFeatureConfig`

```rust
pub struct FormulaFeatureConfig {
    pub feature_count: usize,
    pub include_element_counts: Vec<Element>,
    pub include_ratios: Vec<(Element, Element)>,
}
```

Describes the shape of feature vectors produced by `MolecularFormula::to_feature_vector`.

### `MolecularFormula::to_feature_vector`

```rust
pub fn to_feature_vector(
    &self,
    intensity: f32,
    config: &FormulaFeatureConfig,
) -> Vec<f32>
```

Produces a fixed-length `Vec<f32>` in the order:

1. `monoisotopic_mass`
2. `intensity`
3. `dbe`
4. `mass_defect`
5. counts for each element in `include_element_counts`
6. ratios for each pair in `include_ratios`

`config.feature_count` must equal the resulting length.

## Spectrum decomposer

### `SpectrumDecomposer`

Lower-level decomposer for batch fragment processing.

```rust
pub struct SpectrumDecomposer { ... }

impl SpectrumDecomposer {
    pub fn new(
        min_bounds: Formula,
        max_bounds: Formula,
    ) -> Result<Self, DecompositionError>;

    pub fn decompose_spectrum(
        &self,
        mz_values: &[f64],
        params: &SpectrumDecompositionParams,
    ) -> Vec<(Vec<Formula>, Vec<f64>)>;

    pub fn clean_and_normalize_spectrum(
        &self,
        fragment_masses: &[f64],
        fragment_intensities: &[f64],
        params: &SpectrumDecompositionParams,
        max_allowed_normalized_mass_error_ppm: f64,
    ) -> CleanedAndNormalizedSpectrumResult;
}
```

`SpectrumDecompositionParams` uses `MassTolerance` for its `mass_tolerance`
field. The `max_allowed_normalized_mass_error_ppm` argument to
`clean_and_normalize_spectrum` is intentionally kept in ppm because it is
applied after internal mass-error recalibration.

## Errors

```rust
pub enum DecompositionError {
    NoCandidate,
    InvalidInput(String),
    Other(String),
}
```

- `NoCandidate` — no formula satisfied the constraints.
- `InvalidInput` — malformed input such as a non-positive mass, unsupported
  charge, or mutually exclusive tolerance fields that are both set or both
  missing.
- `Other` — an unexpected internal failure.
