flow-control-detection 0.1.0

Filename heuristics for classifying flow cytometry control files
Documentation
# flow-control-detection

Filename heuristics for classifying flow cytometry control files (unstained, single-stain, sample).

[MIT](LICENSE)

## Overview

`flow-control-detection` provides lightweight, FCS-independent suggestions for control roles and endmember↔filename matching before unmixing or compensation.

## Features

- Regex-based filename normalization and role inference (`ControlRole`)
- Batch `classify_controls` and `match_endmembers` for pairing display labels to control GUIDs
- No FCS parsing dependency

## Installation

```bash
cargo add flow-control-detection
```

Or add it directly to your `Cargo.toml`:

```toml
[dependencies]
flow-control-detection = "0.1.0"
```

## API Usage

### Classify files from filenames

```rust
use flow_control_detection::{
    classify_controls, ControlClassification, ControlRole, FileInfo,
};

fn example() {
    let files: Vec<FileInfo> = vec![
        FileInfo {
            guid: "1".into(),
            filename: "Unstained.fcs".into(),
        },
        FileInfo {
            guid: "2".into(),
            filename: "CD3_FITC.fcs".into(),
        },
    ];
    let classified: Vec<ControlClassification> = classify_controls(&files);

    for c in &classified {
        let role: ControlRole = c.suggested_role;
        let confidence: f32 = c.confidence;
        let label: &String = &c.display_label;
        let guid: &String = &c.guid;
        println!("{guid}: {role:?} ({confidence}) → {label}");
    }
}
```

### Match endmembers / detectors to single-stain controls

```rust
use anyhow::Result;
use flow_control_detection::{
    classify_controls, match_endmembers, ControlClassification, EndmemberMatch, FileInfo,
};

fn example(files: &[FileInfo], detector_names: &[String]) -> Result<()> {
    let classified: Vec<ControlClassification> = classify_controls(files);
    let matches: Vec<EndmemberMatch> = match_endmembers(&classified, detector_names)?;

    for m in matches {
        let endmember: String = m.endmember_name;
        let control_guid: String = m.control_guid;
        let detector: Option<String> = m.detector_name;
        let confidence: f32 = m.confidence;
        println!("{endmember} → {control_guid} ({confidence}) detector={detector:?}");
    }
    Ok(())
}
```

## Testing

```bash
cargo test -p flow-control-detection
```

## License

MIT

## Related crates

- **FCS I/O**[`flow-fcs`]../fcs/ — reading/loading FCS file data
- **Spectral unmixing**[`flow-tru-ols`]../tru-ols/ / [`tru-ols`]../tru-ols-cli/ CLI
- **Peak isolation**[`flow-peak-detection`]../flow-peak-detection/ - identify a peak after a control file is chosen
- **QC**[`peacoqc-rs`]../peacoqc-rs/