use adjustp::Procedure;
use anyhow::Result;
use clap::Parser;
use io::SimpleFrame;
use model::ModelChoice;
use std::path::Path;
mod aggregation;
mod differential_expression;
mod enrich;
mod io;
mod model;
mod norm;
mod utils;
use aggregation::{GeneAggregation, GeneAggregationSelection};
use differential_expression::mageck;
use norm::Normalization;
use utils::{config::Configuration, logging::Logger, Adjustment};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg(short, long)]
input: String,
#[arg(short, long, num_args=1.., required=true)]
controls: Vec<String>,
#[arg(short, long, num_args=1.., required=true)]
treatments: Vec<String>,
#[arg(short, long, default_value = "./results")]
output: String,
#[arg(short, long, default_value = "median-ratio")]
norm: Normalization,
#[arg(short = 'g', long, default_value = "rra")]
agg: GeneAggregationSelection,
#[arg(short, long, default_value = "100")]
permutations: usize,
#[arg(short, long, default_value = "0.25")]
alpha: f64,
#[arg(long)]
no_adjust_alpha: bool,
#[arg(long, default_value = "non-targeting")]
ntc_token: String,
#[arg(short = 'F', long, default_value = "0.1")]
fdr: f64,
#[arg(short = 'G', long, default_value = "5")]
inc_group_size: usize,
#[arg(long)]
inc_product: bool,
#[arg(short, long)]
quiet: bool,
#[arg(short = 'f', long, default_value = "bh")]
correction: Adjustment,
#[arg(short, long, default_value = "wols")]
model_choice: ModelChoice,
#[arg(short, long, default_value = "42")]
seed: u64,
}
fn main() -> Result<()> {
let args = Args::parse();
let path = if Path::new(&args.input).exists() {
args.input
} else {
panic!("Provided Input Does Not Exist: {}", args.input)
};
let agg = match args.agg {
GeneAggregationSelection::RRA => GeneAggregation::AlpaRRA {
alpha: args.alpha,
npermutations: args.permutations,
adjust_alpha: !args.no_adjust_alpha,
fdr: args.fdr,
},
GeneAggregationSelection::Inc => GeneAggregation::Inc {
token: &args.ntc_token,
fdr: args.fdr,
group_size: args.inc_group_size,
use_product: args.inc_product,
},
};
let logger = if args.quiet {
Logger::new_silent()
} else {
Logger::new()
};
let correction = match args.correction {
Adjustment::Bf => Procedure::Bonferroni,
Adjustment::Bh => Procedure::BenjaminiHochberg,
Adjustment::By => Procedure::BenjaminiYekutieli,
};
let config = Configuration::new(
args.norm,
agg,
correction,
args.model_choice,
args.seed,
&args.output,
);
let labels_controls = args.controls;
let labels_treatments = args.treatments;
let frame = SimpleFrame::from_filepath(&path)?;
let mageck_results = mageck(
&frame,
&labels_controls,
&labels_treatments,
&config,
&logger,
);
match mageck_results {
Err(e) => {
println!("ERROR: {e}");
Ok(())
}
Ok(_) => Ok(()),
}
}