use anyhow::Result;
use chrono::Local;
use std::{
collections::VecDeque,
sync::{
atomic::{AtomicBool, AtomicU32, Ordering},
Arc, Mutex,
},
};
fn main() -> Result<()> {
let start_time = Local::now();
let mut args = barcode_count::arguments::Args::new()?;
let sequence_format = barcode_count::info::SequenceFormat::parse_format_file(&args.format)?;
println!("{}\n", sequence_format);
if args.enrich && sequence_format.barcode_num < 2 {
eprintln!("Fewer than 2 counted barcodes. Too few for barcode enrichment. Argument flag is ignored");
args.enrich = false;
}
let mut barcode_conversions = barcode_count::info::BarcodeConversions::new();
if let Some(ref samples) = args.sample_barcodes_option {
barcode_conversions.sample_barcode_file_conversion(samples)?;
barcode_conversions.get_sample_seqs();
}
let results = Arc::new(Mutex::new(barcode_count::info::Results::new(
&barcode_conversions.samples_barcode_hash,
sequence_format.random_barcode,
sequence_format.sample_barcode,
)));
if let Some(ref barcodes) = args.counted_barcodes_option {
barcode_conversions.barcode_file_conversion(barcodes, sequence_format.barcode_num)?;
barcode_conversions.get_barcode_seqs();
}
let sequence_errors = barcode_count::info::SequenceErrors::new();
let exit = Arc::new(AtomicBool::new(false));
let max_errors = barcode_count::info::MaxSeqErrors::new(
args.sample_errors_option,
sequence_format.sample_length_option,
args.barcodes_errors_option,
sequence_format.barcode_lengths.clone(),
args.constant_errors_option,
sequence_format.constant_region_length,
args.min_average_quality_score,
);
println!("{}\n", max_errors);
let total_reads_arc = Arc::new(AtomicU32::new(0));
rayon::scope(|s| {
let seq = Arc::new(Mutex::new(VecDeque::new()));
let finished = Arc::new(AtomicBool::new(false));
let seq_clone = Arc::clone(&seq);
let finished_clone = Arc::clone(&finished);
let exit_clone = Arc::clone(&exit);
let fastq = args.fastq.clone();
let total_reads_arc_clone = Arc::clone(&total_reads_arc);
s.spawn(move |_| {
barcode_count::input::read_fastq(fastq, seq_clone, exit_clone, total_reads_arc_clone)
.unwrap_or_else(|err| {
finished_clone.store(true, Ordering::Relaxed);
panic!("Read Fastq error: {}", err)
});
finished_clone.store(true, Ordering::Relaxed);
});
let shared_mut =
barcode_count::parse::SharedMutData::new(seq, finished, Arc::clone(&results));
for _ in 1..args.threads {
let shared_mut_clone = shared_mut.arc_clone();
let sequence_errors_clone = sequence_errors.arc_clone();
let sequence_format_clone = sequence_format.clone();
let exit_clone = &exit;
let max_errors_clone = max_errors.clone();
let sample_seqs_clone = barcode_conversions.sample_seqs.clone();
let counted_barcode_seqs_clone = barcode_conversions.counted_barcode_seqs.clone();
let min_quality_score = args.min_average_quality_score;
s.spawn(move |_| {
let mut parser = barcode_count::parse::SequenceParser::new(
shared_mut_clone,
sequence_errors_clone,
sequence_format_clone,
max_errors_clone,
sample_seqs_clone,
counted_barcode_seqs_clone,
min_quality_score,
);
parser.parse().unwrap_or_else(|err| {
exit_clone.store(true, Ordering::Relaxed);
panic!("Compute thread panic error: {}", err)
});
})
}
});
println!("{}\n", sequence_errors);
let elapsed_time = Local::now() - start_time;
println!(
"Compute time: {} hours, {} minutes, {}.{} seconds",
elapsed_time.num_hours(),
elapsed_time.num_minutes() % 60,
elapsed_time.num_seconds() % 60,
barcode_count::output::millisecond_decimal(elapsed_time)
);
println!();
println!("-WRITING COUNTS-");
let mut output = barcode_count::output::WriteFiles::new(
results,
sequence_format.clone(),
barcode_conversions.counted_barcodes_hash,
barcode_conversions.samples_barcode_hash,
args,
)
.unwrap_or_else(|err| panic!("Output error: {}", err));
output.write_counts_files()?;
output.write_stats_file(
start_time,
max_errors,
sequence_errors,
total_reads_arc,
sequence_format,
)?;
let elapsed_time = Local::now() - start_time;
println!();
println!(
"Total time: {} hours, {} minutes, {}.{} seconds",
elapsed_time.num_hours(),
elapsed_time.num_minutes() % 60,
elapsed_time.num_seconds() % 60,
barcode_count::output::millisecond_decimal(elapsed_time)
);
Ok(())
}