use anyhow::Result;
use clap::Args;
use std::path::PathBuf;
use uno_core::quant::directms1::{
self as dms1,
input::{self, ReferenceOptions},
uno_adapter, Config,
};
#[derive(Debug, Args)]
pub struct QuantArgs {
#[arg(long,num_args=1..,required_unless_present="samples",conflicts_with="samples")]
s1: Vec<PathBuf>,
#[arg(long,num_args=1..,required_unless_present="samples",conflicts_with="samples")]
s2: Vec<PathBuf>,
#[arg(long, conflicts_with_all=["all_proteins","all_pfms","allowed_proteins","allowed_peptides"])]
samples: Option<PathBuf>,
#[arg(long, requires = "samples")]
exclusive_features: bool,
#[arg(long, requires = "samples", default_value_t = 0)]
min_per_condition: usize,
#[arg(long, requires = "samples")]
feature_competition: bool,
#[arg(long, requires = "samples", default_value = "none")]
peptide_confidence: uno_adapter::PeptideConfidence,
#[arg(long, requires = "samples", default_value_t = 0.01)]
peptide_qvalue: f64,
#[arg(long, requires = "samples", default_value = "apex")]
intensity: uno_adapter::IntensityKind,
#[arg(long, requires = "samples", default_value = "max-intensity")]
reduction: uno_adapter::Reduction,
#[arg(long, default_value_t = 0.01)]
max_protein_qvalue: f64,
#[arg(long)]
out: PathBuf,
#[arg(long, default_value_t = 0)]
min_samples: usize,
#[arg(long, default_value_t = 7)]
min_length: usize,
#[arg(long, default_value_t = 2)]
normalization: u8,
#[arg(long, default_value_t = 2.)]
fold_change: f64,
#[arg(long)]
absolute_fold_change: bool,
#[arg(long, default_value_t = 0.05)]
qvalue: f64,
#[arg(long, default_value = "DECOY_")]
decoy_prefix: String,
#[arg(long, default_value_t = 42)]
seed: u32,
#[arg(long)]
all_proteins: bool,
#[arg(long)]
all_pfms: bool,
#[arg(long)]
allowed_proteins: Option<PathBuf>,
#[arg(long)]
allowed_peptides: Option<PathBuf>,
}
pub fn run(a: QuantArgs) -> Result<()> {
let cfg = Config {
min_samples: a.min_samples,
min_length: a.min_length,
normalization: a.normalization,
fold_change: a.fold_change,
absolute_fold_change: a.absolute_fold_change,
qvalue: a.qvalue,
decoy_prefix: a.decoy_prefix,
seed: a.seed,
};
let options = ReferenceOptions {
all_proteins: a.all_proteins,
all_pfms: a.all_pfms,
allowed_proteins: a.allowed_proteins,
allowed_peptides: a.allowed_peptides,
};
let (data, hashes, mode, admission) = if let Some(path) = &a.samples {
let policy = uno_adapter::AdmissionPolicy {
exclusive_features: a.exclusive_features,
min_per_condition: a.min_per_condition,
feature_competition: a.feature_competition,
peptide_confidence: a.peptide_confidence,
peptide_qvalue: if a.peptide_confidence == uno_adapter::PeptideConfidence::Qvalue {
a.peptide_qvalue
} else {
0.
},
intensity: a.intensity,
reduction: a.reduction,
};
let (data, hashes, audit) =
uno_adapter::load_with_policy(path, &cfg, a.max_protein_qvalue, &policy)?;
(data, hashes, "uno_ms1_adaptation", Some(audit))
} else {
let (data, hashes) = input::reference(&a.s1, &a.s2, &cfg, &options)?;
(data, hashes, "native_directms1quant", None)
};
log::info!("quant input: {} precursor rows", data.rows.len());
let analysis = dms1::analyze(&data, &cfg)?;
log::info!("quant analysis done");
dms1::output::write_with_admission(&a.out, &analysis, &hashes, mode, admission.as_ref())?;
eprintln!(
"{} eligible precursors; {} target proteins; {} significant (experimental, unvalidated)",
analysis.eligible_precursors,
analysis.proteins.len(),
analysis
.proteins
.iter()
.filter(|p| p.bh_pass && p.fc_pass)
.count()
);
Ok(())
}