|
|
@@ -1,133 +1,101 @@
|
|
|
use crate::{
|
|
|
+ collection::{HasOutputs, InitSomatic, Version},
|
|
|
commands::bcftools::{bcftools_keep_pass, BcftoolsConfig},
|
|
|
- runners::{run_wait, CommandRun},
|
|
|
+ config::Config,
|
|
|
+ runners::{run_wait, CommandRun, Run},
|
|
|
};
|
|
|
use anyhow::Context;
|
|
|
use std::{fs, path::Path};
|
|
|
-use tracing::info;
|
|
|
-
|
|
|
-#[derive(Debug, Clone)]
|
|
|
-pub struct SeverusConfig {
|
|
|
- pub bin: String,
|
|
|
- pub result_dir: String,
|
|
|
- pub threads: u8,
|
|
|
- pub vntr_bed: String,
|
|
|
- pub pon: String,
|
|
|
- pub conda_sh: String,
|
|
|
- pub force: bool,
|
|
|
-}
|
|
|
-
|
|
|
-impl Default for SeverusConfig {
|
|
|
- fn default() -> Self {
|
|
|
- Self {
|
|
|
- bin: "/data/tools/Severus/severus.py".to_string(),
|
|
|
- result_dir: "/data/longreads_basic_pipe".to_string(),
|
|
|
- threads: 32,
|
|
|
- vntr_bed: "/data/ref/hs1/vntrs_chm13.bed".to_string(),
|
|
|
- pon: "/data/ref/hs1/PoN_1000G_chm13.tsv.gz".to_string(),
|
|
|
- conda_sh: "/data/miniconda3/etc/profile.d/conda.sh".to_string(),
|
|
|
- force: true,
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
pub struct Severus {
|
|
|
pub id: String,
|
|
|
- pub output_dir: String,
|
|
|
- pub diag_bam: String,
|
|
|
- pub mrd_bam: String,
|
|
|
- pub phased_vcf: String,
|
|
|
- pub output_vcf: String,
|
|
|
- pub vcf_passed: String,
|
|
|
- pub config: SeverusConfig,
|
|
|
+ pub config: Config,
|
|
|
pub log_dir: String,
|
|
|
}
|
|
|
|
|
|
-impl Severus {
|
|
|
- pub fn new(
|
|
|
- id: &str,
|
|
|
- diag_bam: &str,
|
|
|
- mrd_bam: &str,
|
|
|
- phased_vcf: &str,
|
|
|
- config: SeverusConfig,
|
|
|
- ) -> Self {
|
|
|
- let output_dir = format!("{}/{}/diag/severus", config.result_dir, id);
|
|
|
- let output_vcf = format!("{output_dir}/somatic_SVs/severus_somatic.vcf");
|
|
|
- let vcf_passed = format!("{output_dir}/{id}_diag_severus_PASSED.vcf.gz",);
|
|
|
+impl InitSomatic for Severus {
|
|
|
+ fn initialize(id: &str, config: Config) -> anyhow::Result<Self> {
|
|
|
+ let mut output_vcf_exists = Path::new(&config.severus_output_vcf(id)).exists();
|
|
|
+ if config.severus_force && output_vcf_exists {
|
|
|
+ fs::remove_dir_all(config.severus_output_dir(id))?;
|
|
|
+ output_vcf_exists = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if output_vcf_exists {
|
|
|
+ anyhow::bail!("{} already exists.", config.severus_output_vcf(id))
|
|
|
+ }
|
|
|
|
|
|
let log_dir = format!("{}/{}/log/severus", config.result_dir, id);
|
|
|
- Self {
|
|
|
+ if !Path::new(&log_dir).exists() {
|
|
|
+ fs::create_dir_all(&log_dir)
|
|
|
+ .context(format!("Failed to create {log_dir} directory"))?;
|
|
|
+ }
|
|
|
+
|
|
|
+ let phased_germline_vcf = &config.germline_phased_vcf(id);
|
|
|
+ if !Path::new(phased_germline_vcf).exists() {
|
|
|
+ anyhow::bail!("Could not find required phased VCF: {phased_germline_vcf}")
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(Self {
|
|
|
id: id.to_string(),
|
|
|
- output_dir,
|
|
|
- diag_bam: diag_bam.to_string(),
|
|
|
- mrd_bam: mrd_bam.to_string(),
|
|
|
config,
|
|
|
- phased_vcf: phased_vcf.to_string(),
|
|
|
log_dir,
|
|
|
- output_vcf,
|
|
|
- vcf_passed,
|
|
|
- }
|
|
|
+ })
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- pub fn run(&mut self) -> anyhow::Result<()> {
|
|
|
- if self.config.force && Path::new(&self.output_vcf).exists() {
|
|
|
- fs::remove_dir_all(&self.output_dir)?;
|
|
|
- }
|
|
|
-
|
|
|
- if !Path::new(&self.log_dir).exists() {
|
|
|
- fs::create_dir_all(&self.log_dir).expect("Failed to create output directory");
|
|
|
- }
|
|
|
+impl Run for Severus {
|
|
|
+ fn run(&mut self) -> anyhow::Result<()> {
|
|
|
+ let id = &self.id;
|
|
|
+ let output_vcf = &self.config.severus_output_vcf(id);
|
|
|
+ let passed_vcf = &self.config.severus_passed_vcf(id);
|
|
|
|
|
|
// Run command if output VCF doesn't exist
|
|
|
- if !Path::new(&self.output_vcf).exists() {
|
|
|
- let severus_args = [
|
|
|
- "--target-bam",
|
|
|
- &self.diag_bam,
|
|
|
- "--control-bam",
|
|
|
- &self.mrd_bam,
|
|
|
- "--phasing-vcf",
|
|
|
- &self.phased_vcf,
|
|
|
- "--out-dir",
|
|
|
- &self.output_dir,
|
|
|
- "-t",
|
|
|
- &self.config.threads.to_string(),
|
|
|
- "--write-alignments",
|
|
|
- "--use-supplementary-tag",
|
|
|
- "--resolve-overlaps",
|
|
|
- "--between-junction-ins",
|
|
|
- "--vntr-bed",
|
|
|
- &self.config.vntr_bed,
|
|
|
- ];
|
|
|
- let args = [
|
|
|
- "-c",
|
|
|
- &format!("source {} && conda activate severus_env && {} {}", self.config.conda_sh, self.config.bin, severus_args.join(" ")),
|
|
|
- ];
|
|
|
- let mut cmd_run = CommandRun::new("bash", &args);
|
|
|
- let report = run_wait(&mut cmd_run).context(format!(
|
|
|
- "Error while running `severus.py {}`",
|
|
|
- args.join(" ")
|
|
|
- ))?;
|
|
|
+ let severus_args = [
|
|
|
+ "--target-bam",
|
|
|
+ &self.config.tumoral_bam(id),
|
|
|
+ "--control-bam",
|
|
|
+ &self.config.normal_bam(id),
|
|
|
+ "--phasing-vcf",
|
|
|
+ &self.config.germline_phased_vcf(id),
|
|
|
+ "--out-dir",
|
|
|
+ &self.config.severus_output_dir(id),
|
|
|
+ "-t",
|
|
|
+ &self.config.severus_threads.to_string(),
|
|
|
+ "--write-alignments",
|
|
|
+ "--use-supplementary-tag",
|
|
|
+ "--resolve-overlaps",
|
|
|
+ "--between-junction-ins",
|
|
|
+ "--vntr-bed",
|
|
|
+ &self.config.vntrs_bed,
|
|
|
+ ];
|
|
|
+ let args = [
|
|
|
+ "-c",
|
|
|
+ &format!(
|
|
|
+ "source {} && conda activate severus_env && {} {}",
|
|
|
+ self.config.conda_sh,
|
|
|
+ self.config.severus_bin,
|
|
|
+ severus_args.join(" ")
|
|
|
+ ),
|
|
|
+ ];
|
|
|
+ let mut cmd_run = CommandRun::new("bash", &args);
|
|
|
+ let report = run_wait(&mut cmd_run).context(format!(
|
|
|
+ "Error while running `severus.py {}`",
|
|
|
+ args.join(" ")
|
|
|
+ ))?;
|
|
|
|
|
|
- let log_file = format!("{}/severus_", self.log_dir);
|
|
|
- report
|
|
|
- .save_to_file(&log_file)
|
|
|
- .context(format!("Error while writing logs into {log_file}"))?;
|
|
|
- } else {
|
|
|
- info!("Severus output vcf already exists");
|
|
|
- }
|
|
|
+ let log_file = format!("{}/severus_", self.log_dir);
|
|
|
+ report
|
|
|
+ .save_to_file(&log_file)
|
|
|
+ .context(format!("Error while writing logs into {log_file}"))?;
|
|
|
|
|
|
// Keep PASS
|
|
|
- if !Path::new(&self.vcf_passed).exists() {
|
|
|
- let report = bcftools_keep_pass(
|
|
|
- &self.output_vcf,
|
|
|
- &self.vcf_passed,
|
|
|
- BcftoolsConfig::default(),
|
|
|
- )
|
|
|
- .context(format!(
|
|
|
- "Error while running bcftools keep PASS for {}",
|
|
|
- &self.output_vcf
|
|
|
- ))?;
|
|
|
+ if !Path::new(passed_vcf).exists() && Path::new(output_vcf).exists() {
|
|
|
+ let report = bcftools_keep_pass(output_vcf, passed_vcf, BcftoolsConfig::default())
|
|
|
+ .context(format!(
|
|
|
+ "Error while running bcftools keep PASS for {output_vcf}"
|
|
|
+ ))?;
|
|
|
let log_file = format!("{}/bcftools_pass", self.log_dir);
|
|
|
report
|
|
|
.save_to_file(&log_file)
|
|
|
@@ -136,3 +104,31 @@ impl Severus {
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+impl HasOutputs for Severus {
|
|
|
+ fn has_output(&self, id: &str) -> (bool, bool) {
|
|
|
+ let output = &self.config.severus_passed_vcf(id);
|
|
|
+ let passed = &self.config.severus_passed_vcf(id);
|
|
|
+ (Path::new(output).exists(), Path::new(passed).exists())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Version for Severus {
|
|
|
+ fn version(config: &Config) -> anyhow::Result<String> {
|
|
|
+ let args = [
|
|
|
+ "-c",
|
|
|
+ &format!(
|
|
|
+ "source {} && conda activate severus_env && {} {}",
|
|
|
+ config.conda_sh, config.severus_bin, "--version"
|
|
|
+ ),
|
|
|
+ ];
|
|
|
+ let mut cmd_run = CommandRun::new("bash", &args);
|
|
|
+ let report = run_wait(&mut cmd_run).context("Error while running `severus --version`")?;
|
|
|
+ let v = match report.log.split_once(':') {
|
|
|
+ Some((_, value)) => value.trim(),
|
|
|
+ None => anyhow::bail!("Error while parsing `severus --version`"),
|
|
|
+ };
|
|
|
+
|
|
|
+ Ok(v.to_string())
|
|
|
+ }
|
|
|
+}
|