ソースを参照

Integration to somatic pipe Severus Savana DeepSomatic / LongPhase up

Thomas 11 ヶ月 前
コミット
a1b3c01b01

+ 2 - 0
src/annotation/mod.rs

@@ -88,6 +88,7 @@ pub enum Caller {
     NanomonSVSolo,
     Savana,
     Severus,
+    DeepSomatic,
 }
 
 impl fmt::Display for Caller {
@@ -99,6 +100,7 @@ impl fmt::Display for Caller {
             Caller::NanomonSVSolo => write!(f, "NanomonSV-solo"),
             Caller::Savana => write!(f, "Savana"),
             Caller::Severus => write!(f, "Severus"),
+            Caller::DeepSomatic => write!(f, "DeepSomatic"),
         }
     }
 }

+ 162 - 0
src/callers/deep_somatic.rs

@@ -0,0 +1,162 @@
+use std::{fs, path::Path};
+
+use anyhow::Context;
+use log::info;
+use rayon::prelude::*;
+
+use crate::{
+    annotation::{Annotation, Annotations, Caller, CallerCat},
+    collection::{vcf::Vcf, Initialize},
+    commands::bcftools::{bcftools_keep_pass, BcftoolsConfig},
+    config::Config,
+    helpers::path_prefix,
+    io::vcf::read_vcf,
+    runners::{run_wait, DockerRun, Run},
+    variant::{
+        variant::{RunnerVariants, Variants},
+        variant_collection::VariantCollection,
+    },
+};
+
+#[derive(Debug)]
+pub struct DeepSomatic {
+    pub id: String,
+    pub output_dir: String,
+    pub output_vcf: String,
+    pub vcf_passed: String,
+    pub log_dir: String,
+    pub config: Config,
+}
+
+impl Initialize for DeepSomatic {
+    fn initialize(id: &str, config: Config) -> anyhow::Result<Self> {
+        let id = id.to_string();
+        info!("Initializing DeepSomatic for {id}.");
+
+        let log_dir = format!("{}/{}/log/deepsomatic", config.result_dir, &id);
+        if !Path::new(&log_dir).exists() {
+            fs::create_dir_all(&log_dir)
+                .context(format!("Failed  to create {log_dir} directory"))?;
+        }
+
+        let output_dir = config.deepsomatic_output_dir(&id);
+        fs::create_dir_all(&output_dir).context(format!("Can't create dir: {output_dir}"))?;
+
+        let output_vcf = format!(
+            "{}/{}_{}_DeepSomatic.vcf.gz",
+            output_dir, id, config.tumoral_name
+        );
+        let vcf_passed = format!("{}_PASSED.vcf.gz", path_prefix(&output_vcf)?);
+
+        Ok(Self {
+            id,
+            config,
+            log_dir,
+            output_dir,
+            output_vcf,
+            vcf_passed,
+        })
+    }
+}
+
+impl Run for DeepSomatic {
+    fn run(&mut self) -> anyhow::Result<()> {
+        if !Path::new(&self.output_vcf).exists() {
+            let mut docker_run = DockerRun::new(&[
+                "run",
+                "-d",
+                "-v",
+                "/data:/data",
+                "-v",
+                &format!("{}:/output", self.output_dir),
+                &format!("google/deepsomatic:{}", self.config.deepsomatic_bin_version),
+                "run_deepsomatic",
+                &format!("--model_type={}", self.config.deepsomatic_model_type),
+                "--ref",
+                &self.config.reference,
+                "--reads_normal",
+                &self.config.normal_bam(&self.id),
+                "--reads_tumor",
+                &self.config.tumoral_bam(&self.id),
+                "--output_vcf",
+                &format!(
+                    "/output/{}_{}_DeepSomatic.vcf.gz",
+                    self.id, self.config.tumoral_name
+                ),
+                "--output_gvcf",
+                &format!(
+                    "/output/{}_{}_DeepSomatic.g.vcf.gz",
+                    self.id, self.config.tumoral_name
+                ),
+                &format!("--num_shards={}", self.config.deepsomatic_threads),
+                "--logging_dir",
+                &format!(
+                    "/output/{}_{}_DeepSomatic_logs",
+                    self.id, self.config.tumoral_name
+                ),
+                "--vcf_stats_report=true",
+                "--dry_run=false",
+                "--sample_name_tumor",
+                &format!("{}_{}", self.id, self.config.tumoral_name),
+                "--sample_name_normal",
+                &format!("{}_{}", self.id, self.config.normal_name),
+            ]);
+            let report = run_wait(&mut docker_run)
+                .context(format!("Erreur while running DeepSomatic for {}.", self.id))?;
+            report
+                .save_to_file(&format!("{}/deepvariant_", self.log_dir))
+                .context("Can't save DeepVariant logs")?;
+        }
+
+        // Keep PASS
+        if !Path::new(&self.vcf_passed).exists() {
+            info!("Filtering PASS variants");
+            let report = bcftools_keep_pass(
+                &self.output_vcf,
+                &self.vcf_passed,
+                BcftoolsConfig::default(),
+            )
+            .unwrap();
+            report
+                .save_to_file(&format!("{}/bcftools_pass_", self.log_dir))
+                .unwrap();
+        }
+
+        Ok(())
+    }
+}
+
+impl CallerCat for DeepSomatic {
+    fn caller_cat(&self) -> (Caller, Annotation) {
+        (Caller::DeepSomatic, Annotation::Somatic)
+    }
+}
+
+impl Variants for DeepSomatic {
+    fn variants(&self, annotations: &Annotations) -> anyhow::Result<VariantCollection> {
+        let (caller, category) = self.caller_cat();
+        let add = vec![Annotation::Callers(caller.clone()), category.clone()];
+        info!(
+            "Loading variants from {} {}: {}",
+            caller, category, self.vcf_passed
+        );
+        let variants = read_vcf(&self.vcf_passed)?;
+        variants.par_iter().for_each(|v| {
+            annotations.insert_update(v.hash(), &add);
+        });
+        info!(
+            "{} {}, {} variants loaded.",
+            caller,
+            category,
+            variants.len()
+        );
+        Ok(VariantCollection {
+            variants,
+            vcf: Vcf::new(self.vcf_passed.clone().into())?,
+            caller,
+            category,
+        })
+    }
+}
+
+impl RunnerVariants for DeepSomatic {}

+ 1 - 0
src/callers/mod.rs

@@ -7,6 +7,7 @@ pub mod deep_variant;
 pub mod nanomonsv;
 pub mod savana;
 pub mod severus;
+pub mod deep_somatic;
 
 #[derive(Debug)]
 pub enum CallersSolo {

+ 85 - 39
src/callers/savana.rs

@@ -1,22 +1,31 @@
 use crate::{
     annotation::{Annotation, Annotations, Caller, CallerCat},
     collection::{vcf::Vcf, HasOutputs, Initialize, Version},
-    commands::bcftools::{bcftools_keep_pass, BcftoolsConfig},
+    commands::{
+        bcftools::{bcftools_keep_pass, BcftoolsConfig},
+        longphase::{LongphaseConfig, LongphaseHap, LongphasePhase},
+    },
     config::Config,
     helpers::force_or_not,
     io::vcf::read_vcf,
     runners::{run_wait, CommandRun, Run},
-    variant::{variant::Variants, variant_collection::VariantCollection},
+    variant::{
+        variant::{RunnerVariants, Variants},
+        variant_collection::VariantCollection,
+    },
 };
 use anyhow::Context;
-use rayon::prelude::*;
 use log::info;
+use rayon::prelude::*;
 use std::{fs, path::Path};
 
 #[derive(Debug)]
 pub struct Savana {
     pub id: String,
     pub passed_vcf: String,
+    pub phased_germline_vcf: String,
+    pub normal_hp_bam: String,
+    pub tumoral_hp_bam: String,
     pub config: Config,
     pub log_dir: String,
 }
@@ -28,15 +37,27 @@ impl Initialize for Savana {
             fs::create_dir_all(&log_dir)
                 .context(format!("Failed  to create {log_dir} directory"))?;
         }
-        // Check for haplotagged bam
+
+        // Check for phased germline vcf
+        let phased_germline_vcf = config.constit_phased_vcf(id);
+        if !Path::new(&phased_germline_vcf).exists() {
+            LongphasePhase::initialize(id, config.clone())?.run()?;
+        }
+
+        let normal_hp_bam = config.normal_haplotagged_bam(id);
+        let tumoral_hp_bam = config.tumoral_haplotagged_bam(id);
 
         let passed_vcf = config.savana_passed_vcf(id);
+        fs::create_dir_all(config.savana_output_dir(id))?;
 
         Ok(Self {
             id: id.to_string(),
             passed_vcf,
             config,
             log_dir,
+            phased_germline_vcf,
+            normal_hp_bam,
+            tumoral_hp_bam,
         })
     }
 }
@@ -50,44 +71,67 @@ impl Run for Savana {
         info!("Running Savana v{}", Savana::version(&self.config)?);
 
         let id = &self.id;
-        let savana_args = [
-            // "run",
-            "--tumour",
-            &self.config.tumoral_haplotagged_bam(id),
-            "--normal",
-            &self.config.normal_haplotagged_bam(id),
-            "--outdir",
-            &self.config.savana_output_dir(id),
-            "--ref",
-            &self.config.reference,
-            "--phased_vcf",
-            &self.config.germline_phased_vcf(id),
-            "--no_blacklist",
-            "--threads",
-            &self.config.savana_threads.to_string(),
-        ];
-        let args = [
-            "-c",
-            &format!(
-                "source {} && conda activate savana && {} {}",
-                self.config.conda_sh,
-                self.config.savana_bin,
-                savana_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 output_vcf = &self.config.savana_output_vcf(id);
+        if !Path::new(&output_vcf).exists() {
+            // Check for haplotagged bam
+            if !Path::new(&self.normal_hp_bam).exists() {
+                LongphaseHap::new(
+                    id,
+                    &self.config.normal_bam(id),
+                    &self.phased_germline_vcf,
+                    LongphaseConfig::default(),
+                )
+                .run()?;
+            }
 
-        let log_file = format!("{}/savana_", self.log_dir);
-        report
-            .save_to_file(&log_file)
-            .context(format!("Error while writing logs into {log_file}"))?;
+            if !Path::new(&self.tumoral_hp_bam).exists() {
+                LongphaseHap::new(
+                    id,
+                    &self.config.tumoral_bam(id),
+                    &self.phased_germline_vcf,
+                    LongphaseConfig::default(),
+                )
+                .run()?;
+            }
+
+            let savana_args = [
+                // "run",
+                "--tumour",
+                &self.tumoral_hp_bam,
+                "--normal",
+                &self.normal_hp_bam,
+                "--outdir",
+                &self.config.savana_output_dir(id),
+                "--ref",
+                &self.config.reference,
+                "--phased_vcf",
+                &self.phased_germline_vcf,
+                "--no_blacklist",
+                "--threads",
+                &self.config.savana_threads.to_string(),
+            ];
+            let args = [
+                "-c",
+                &format!(
+                    "source {} && conda activate savana && {} {}",
+                    self.config.conda_sh,
+                    self.config.savana_bin,
+                    savana_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!("{}/savana_", self.log_dir);
+            report
+                .save_to_file(&log_file)
+                .context(format!("Error while writing logs into {log_file}"))?;
+        }
 
         // Keep PASS
-        let output_vcf = &self.config.savana_output_vcf(id);
         if !Path::new(&self.passed_vcf).exists() && Path::new(output_vcf).exists() {
             let report =
                 bcftools_keep_pass(output_vcf, &self.passed_vcf, BcftoolsConfig::default())
@@ -168,3 +212,5 @@ impl Variants for Savana {
         })
     }
 }
+
+impl RunnerVariants for Savana {}

+ 64 - 53
src/callers/severus.rs

@@ -1,7 +1,10 @@
 use crate::{
     annotation::{Annotation, Annotations, Caller, CallerCat},
     collection::{vcf::Vcf, HasOutputs, Initialize, InitializeSolo, Version},
-    commands::bcftools::{bcftools_keep_pass, BcftoolsConfig},
+    commands::{
+        bcftools::{bcftools_keep_pass_precise, BcftoolsConfig},
+        longphase::LongphasePhase,
+    },
     config::Config,
     io::vcf::read_vcf,
     runners::{run_wait, CommandRun, Run},
@@ -11,8 +14,8 @@ use crate::{
     },
 };
 use anyhow::Context;
-use rayon::prelude::*;
 use log::{debug, info};
+use rayon::prelude::*;
 use std::{fs, path::Path};
 
 #[derive(Debug)]
@@ -24,14 +27,10 @@ pub struct Severus {
 
 impl Initialize for Severus {
     fn initialize(id: &str, config: Config) -> anyhow::Result<Self> {
-        let mut output_vcf_exists = Path::new(&config.severus_output_vcf(id)).exists();
+        info!("Initialize Severus for {id}.");
+        let 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);
@@ -42,8 +41,10 @@ impl Initialize for Severus {
 
         let phased_germline_vcf = &config.constit_phased_vcf(id);
         if !Path::new(phased_germline_vcf).exists() {
-            anyhow::bail!("Could not find required phased VCF: {phased_germline_vcf}")
+            LongphasePhase::initialize(id, config.clone())?.run()?;
+            // anyhow::bail!("Could not find required phased VCF: {phased_germline_vcf}")
         }
+        fs::create_dir_all(config.severus_output_dir(id))?;
 
         Ok(Self {
             id: id.to_string(),
@@ -55,54 +56,59 @@ impl Initialize for Severus {
 
 impl Run for Severus {
     fn run(&mut self) -> anyhow::Result<()> {
+        // TODO make that work
         info!("Running Severus v{}", Severus::version(&self.config)?);
 
         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
-        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(" ")
-        ))?;
+        if !Path::new(output_vcf).exists() {
+            // Run command if output VCF doesn't exist
+            let severus_args = [
+                "--target-bam",
+                &self.config.tumoral_bam(id),
+                "--control-bam",
+                &self.config.normal_bam(id),
+                "--phasing-vcf",
+                &self.config.constit_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}"))?;
+            let log_file = format!("{}/severus_", self.log_dir);
+            report
+                .save_to_file(&log_file)
+                .context(format!("Error while writing logs into {log_file}"))?;
+        } else {
+            debug!("")
+        }
 
         // Keep PASS
         if !Path::new(passed_vcf).exists() && Path::new(output_vcf).exists() {
-            let report = bcftools_keep_pass(output_vcf, passed_vcf, BcftoolsConfig::default())
+            let report = bcftools_keep_pass_precise(output_vcf, passed_vcf, BcftoolsConfig::default())
                 .context(format!(
                     "Error while running bcftools keep PASS for {output_vcf}"
                 ))?;
@@ -155,14 +161,21 @@ impl Variants for Severus {
         let (caller, category) = self.caller_cat();
         let add = vec![Annotation::Callers(caller.clone()), category.clone()];
         info!(
-            "Loading variants from Severus {}: {vcf_passed} with annotations: {:?}",
-            self.id, add
+            "Loading variants from {} {}: {}",
+            caller, category, vcf_passed
         );
+
         let variants = read_vcf(&vcf_passed)?;
 
         variants.par_iter().for_each(|v| {
             annotations.insert_update(v.hash(), &add);
         });
+        info!(
+            "{} {}, {} variants loaded.",
+            caller,
+            category,
+            variants.len()
+        );
         Ok(VariantCollection {
             variants,
             vcf: Vcf::new(vcf_passed.into())?,
@@ -206,7 +219,7 @@ impl Run for SeverusSolo {
 
         let output_vcf = &self.config.severus_solo_output_vcf(id, time);
         let passed_vcf = &self.config.severus_solo_passed_vcf(id, time);
-        
+
         if !Path::new(output_vcf).exists() {
             // Run command if output VCF doesn't exist
             let severus_args = [
@@ -242,15 +255,13 @@ impl Run for SeverusSolo {
             report
                 .save_to_file(&log_file)
                 .context(format!("Error while writing logs into {log_file}"))?;
-
         } else {
             debug!("Severus output vcf already exists.");
         }
 
-
         // Keep PASS
         if !Path::new(passed_vcf).exists() && Path::new(output_vcf).exists() {
-            let report = bcftools_keep_pass(output_vcf, passed_vcf, BcftoolsConfig::default())
+            let report = bcftools_keep_pass_precise(output_vcf, passed_vcf, BcftoolsConfig::default())
                 .context(format!(
                     "Error while running bcftools keep PASS for {output_vcf}"
                 ))?;

+ 72 - 0
src/commands/bcftools.rs

@@ -72,6 +72,58 @@ pub fn bcftools_keep_pass(
     Ok(res)
 }
 
+pub fn bcftools_keep_pass_precise(
+    input: &str,
+    output: &str,
+    config: BcftoolsConfig,
+) -> anyhow::Result<RunReport> {
+    if !Path::new(input).exists() {
+        anyhow::bail!("File doesnt exist {input}")
+    }
+    // First sort
+    let tmp_file = format!("/tmp/{}", Uuid::new_v4());
+    let mut cmd_run = CommandRun::new(&config.bin, &["sort", input, "-o", &tmp_file]);
+    let _ = run_wait(&mut cmd_run)?;
+
+    // 2. norm
+    let tmp2_file = format!("/tmp/{}", Uuid::new_v4());
+    let mut cmd_run = CommandRun::new(
+        &config.bin,
+        &[
+            "norm",
+            "--threads",
+            &config.threads.to_string(),
+            "-a",
+            "--atom-overlaps",
+            ".",
+            &tmp_file,
+            "-o",
+            &tmp2_file,
+        ],
+    );
+    let _ = run_wait(&mut cmd_run)?;
+    fs::remove_file(tmp_file)?;
+
+    // Then filter
+    let mut cmd_run = CommandRun::new(
+        &config.bin,
+        &[
+            "view",
+            "--write-index",
+            "--threads",
+            &config.threads.to_string(),
+            "-e",
+            "INFO/IMPRECISE==1 || FILTER!=\"PASS\"",
+            &tmp2_file,
+            "-o",
+            output,
+        ],
+    );
+    let res = run_wait(&mut cmd_run)?;
+    fs::remove_file(tmp2_file)?;
+    Ok(res)
+}
+
 pub fn bcftools_concat(
     inputs: Vec<String>,
     output: &str,
@@ -121,3 +173,23 @@ pub fn bcftools_index(vcf: &str, config: &BcftoolsConfig) -> anyhow::Result<()>
         .context(format!("Error while running `bcftools {}`", args.join(" ")))?;
     Ok(())
 }
+
+pub fn bcftools_compress(
+    in_vcf: &str,
+    out_vcf: &str,
+    config: &BcftoolsConfig,
+) -> anyhow::Result<()> {
+    let args = [
+        "view",
+        "--threads",
+        &config.threads.to_string(),
+        in_vcf,
+        "-Oz",
+        "-o",
+        out_vcf,
+    ];
+    let mut cmd_run = CommandRun::new(&config.bin, &args);
+    let _ = run_wait(&mut cmd_run)
+        .context(format!("Error while running `bcftools {}`", args.join(" ")))?;
+    Ok(())
+}

+ 46 - 28
src/commands/longphase.rs

@@ -1,5 +1,9 @@
 use crate::{
-    collection::{Initialize, InitializeSolo}, config::Config, helpers::path_prefix, runners::{run_wait, CommandRun, Run}
+    collection::{Initialize, InitializeSolo},
+    commands::bcftools::{bcftools_compress, bcftools_index},
+    config::Config,
+    helpers::path_prefix,
+    runners::{run_wait, CommandRun, Run},
 };
 use anyhow::Context;
 use duct::cmd;
@@ -50,6 +54,7 @@ impl LongphaseHap {
         let log_dir = format!("{}/{}/log/longphase", config.result_dir, id);
 
         let bam = Path::new(bam);
+        // TODO change that use config.haplotagged_bam_tag_name
         let new_fn = format!("{}_HP", bam.file_stem().unwrap().to_str().unwrap());
         let bam_hp = bam.with_file_name(new_fn);
 
@@ -119,6 +124,7 @@ impl LongphaseHap {
 // /data/tools/longphase_linux-x64 phase -s ClairS/clair3_normal_tumoral_germline_output.vcf.gz -b CUNY_diag_hs1_hp.bam -r /data/ref/hs1/chm13v2.0.fa -t 155 --ont -o ClairS/clair3_normal_tumoral_germline_output_PS
 #[derive(Debug)]
 pub struct LongphasePhase {
+    pub id: String,
     pub vcf: String,
     pub out_prefix: String,
     pub bam: String,
@@ -140,6 +146,7 @@ impl Initialize for LongphasePhase {
         let modcall_vcf = config.longphase_modcall_vcf(id, "diag");
 
         Ok(LongphasePhase {
+            id: id.to_string(),
             config,
             log_dir,
             vcf,
@@ -153,35 +160,46 @@ impl Initialize for LongphasePhase {
 impl Run for LongphasePhase {
     fn run(&mut self) -> anyhow::Result<()> {
         info!("Running longphase phase for: {}", self.vcf);
-        info!("Savong longphase phase in: {}", self.out_prefix);
+        info!("Saving longphase phase results in: {}", self.out_prefix);
 
-        let args = [
-            "phase",
-            "-s",
-            &self.vcf,
-            "-b",
-            &self.bam,
-            "-r",
-            &self.config.reference,
-            "--mod-file",
-            &self.modcall_vcf,
-            "-t",
-            &self.config.longphase_threads.to_string(),
-            "--ont",
-            "-o",
-            &self.out_prefix,
-        ];
-        let mut cmd_run = CommandRun::new(&self.config.longphase_bin, &args);
-        let report = run_wait(&mut cmd_run).context(format!(
-            "Error while running `{} {}`",
-            self.config.longphase_bin,
-            args.join(" ")
-        ))?;
+        let final_vcf = self.config.constit_phased_vcf(&self.id);
+        if !Path::new(&final_vcf).exists() {
+            let args = [
+                "phase",
+                "-s",
+                &self.vcf,
+                "-b",
+                &self.bam,
+                "-r",
+                &self.config.reference,
+                "--mod-file",
+                &self.modcall_vcf,
+                "-t",
+                &self.config.longphase_threads.to_string(),
+                "--ont",
+                "-o",
+                &self.out_prefix,
+            ];
+            let mut cmd_run = CommandRun::new(&self.config.longphase_bin, &args);
+            let report = run_wait(&mut cmd_run).context(format!(
+                "Error while running `{} {}`",
+                self.config.longphase_bin,
+                args.join(" ")
+            ))?;
 
-        let log_file = format!("{}/longphase_phase_", self.log_dir);
-        report
-            .save_to_file(&log_file)
-            .context(format!("Error while writing logs into {log_file}"))?;
+            let log_file = format!("{}/longphase_phase_", self.log_dir);
+            report
+                .save_to_file(&log_file)
+                .context(format!("Error while writing logs into {log_file}"))?;
+
+            bcftools_compress(
+                &format!("{}.vcf", self.out_prefix),
+                &final_vcf,
+                &BcftoolsConfig::default(),
+            )?;
+            bcftools_index(&final_vcf, &BcftoolsConfig::default())?;
+            fs::remove_file(format!("{}.vcf", self.out_prefix))?;
+        }
         Ok(())
     }
 }

+ 30 - 7
src/config.rs

@@ -34,6 +34,11 @@ pub struct Config {
     pub deepvariant_bin_version: String,
     pub deepvariant_model_type: String,
     pub deepvariant_force: bool,
+    pub deepsomatic_output_dir: String,
+    pub deepsomatic_threads: u8,
+    pub deepsomatic_bin_version: String,
+    pub deepsomatic_model_type: String,
+
     pub clairs_threads: u8,
     pub clairs_force: bool,
     pub clairs_platform: String,
@@ -75,14 +80,14 @@ impl Default for Config {
 
             tumoral_name: "diag".to_string(),
             normal_name: "mrd".to_string(),
-            haplotagged_bam_tag_name: "hp".to_string(),
+            haplotagged_bam_tag_name: "HP".to_string(),
 
             //
             mask_bed: "{result_dir}/{id}/diag/mask.bed".to_string(),
 
-            germline_phased_vcf:
-                "{result_dir}/{id}/diag/ClairS/clair3_normal_germline_output_PS.vcf"
-                    .to_string(),
+            germline_phased_vcf: "{result_dir}/{id}/diag/{id}_variants_constit_phased.vcf.gz
+"
+            .to_string(),
             conda_sh: "/data/miniconda3/etc/profile.d/conda.sh".to_string(),
 
             // DeepVariant
@@ -92,6 +97,12 @@ impl Default for Config {
             deepvariant_model_type: "ONT_R104".to_string(),
             deepvariant_force: false,
 
+            // DeepSomatic
+            deepsomatic_output_dir: "{result_dir}/{id}/{time}/DeepSomatic".to_string(),
+            deepsomatic_threads: 155,
+            deepsomatic_bin_version: "1.8.0".to_string(),
+            deepsomatic_model_type: "ONT".to_string(),
+
             // ClairS
             clairs_output_dir: "{result_dir}/{id}/diag/ClairS".to_string(),
             clairs_threads: 155,
@@ -135,7 +146,8 @@ impl Default for Config {
             nanomonsv_passed_vcf: "{output_dir}/{id}_diag_nanomonsv_PASSED.vcf.gz".to_string(),
 
             nanomonsv_solo_output_dir: "{result_dir}/{id}/{time}/nanomonsv-solo".to_string(),
-            nanomonsv_solo_passed_vcf: "{output_dir}/{id}_{time}_nanomonsv-solo_PASSED.vcf.gz".to_string(),
+            nanomonsv_solo_passed_vcf: "{output_dir}/{id}_{time}_nanomonsv-solo_PASSED.vcf.gz"
+                .to_string(),
 
             // Pipe
             solo_min_constit_depth: 5,
@@ -264,6 +276,14 @@ impl Config {
         .replace("{time}", time)
     }
 
+    // DeepSomatic
+    pub fn deepsomatic_output_dir(&self, id: &str) -> String {
+        self.deepsomatic_output_dir
+            .replace("{result_dir}", &self.result_dir)
+            .replace("{id}", id)
+            .replace("{time}", &self.tumoral_name)
+    }
+
     // ClairS
     pub fn clairs_output_dir(&self, id: &str) -> String {
         self.clairs_output_dir
@@ -323,7 +343,6 @@ impl Config {
             .replace("{time}", time)
     }
 
-
     // Savana
     pub fn savana_output_dir(&self, id: &str) -> String {
         self.savana_output_dir
@@ -391,7 +410,11 @@ impl Config {
     }
 
     pub fn constit_phased_vcf(&self, id: &str) -> String {
-        format!("{}/{}_variants_constit_PS.vcf.gz", self.tumoral_dir(id), id)
+        format!(
+            "{}/{}_variants_constit_phased.vcf.gz",
+            self.tumoral_dir(id),
+            id
+        )
     }
 
     pub fn modkit_summary_file(&self, id: &str, time: &str) -> String {

+ 0 - 1
src/helpers.rs

@@ -1,5 +1,4 @@
 use anyhow::Context;
-use log::warn;
 use serde::{Deserialize, Serialize};
 use std::{
     cmp::Ordering,

+ 14 - 2
src/pipes/somatic.rs

@@ -3,7 +3,10 @@ use std::{fs::File, sync::Arc};
 
 use crate::{
     annotation::{Annotation, Annotations, Caller},
-    callers::{clairs::ClairS, deep_variant::DeepVariant, nanomonsv::NanomonSV},
+    callers::{
+        clairs::ClairS, deep_somatic::DeepSomatic, deep_variant::DeepVariant, nanomonsv::NanomonSV,
+        savana::Savana, severus::Severus,
+    },
     collection::{Initialize, InitializeSolo},
     config::Config,
     init_solo_callers, init_somatic_callers,
@@ -95,7 +98,16 @@ impl Run for Somatic {
         // Initalize variants collections
         info!("Initialization of callers...");
 
-        let mut callers = init_somatic_callers!(&id, &config, ClairS, NanomonSV);
+        let mut callers = init_somatic_callers!(
+            &id,
+            &config,
+            ClairS,
+            NanomonSV,
+            Severus,
+            Savana,
+            DeepSomatic
+        );
+
         callers.extend(init_solo_callers!(
             &id,
             &config,

+ 1 - 62
src/variant/variant.rs

@@ -6,7 +6,6 @@ use crate::{
     variant::variant_collection::VariantCollection,
 };
 use anyhow::{anyhow, Context, Ok};
-use blake3::Hasher;
 use rayon::prelude::*;
 use serde::{Deserialize, Serialize};
 use std::{cmp::Ordering, collections::HashSet, fmt, hash::Hash, str::FromStr};
@@ -33,18 +32,6 @@ impl PartialEq for VcfVariant {
     }
 }
 
-// impl Hash for VcfVariant {
-//     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
-//         let mut hasher = Hasher::new();
-//         hasher.update(&self.position.contig.to_ne_bytes()); // Convert position to bytes
-//         hasher.update(&self.position.position.to_ne_bytes()); // Convert position to bytes
-//         hasher.update(self.reference.to_string().as_bytes()); // Reference string as bytes
-//         hasher.update(self.alternative.to_string().as_bytes()); // Alternative string as bytes
-//         let hash = hasher.finalize();
-//         state.write(&hash.as_bytes()[..16]);
-//     }
-// }
-
 impl Eq for VcfVariant {}
 
 impl FromStr for VcfVariant {
@@ -82,6 +69,7 @@ impl FromStr for VcfVariant {
             .parse()
             .context(format!("Can't parse alternative from: {s}"))?;
 
+        // Blake3 128 bytes Hash
         let mut hasher = blake3::Hasher::new();
         hasher.update(&position.contig.to_ne_bytes()); // Convert position to bytes
         hasher.update(&position.position.to_ne_bytes()); // Convert position to bytes
@@ -168,55 +156,6 @@ impl VcfVariant {
         self.infos.0.iter().any(|i| matches!(i, Info::SVTYPE(_)))
     }
 
-    // pub fn into_sv_vcf_row() {
-    //     let vcf_position: VcfPosition = self.position.clone().into();
-    //     let (contig, position) = vcf_position.into();
-    //
-    //     let mut columns = vec![
-    //         contig,
-    //         position,
-    //         self.i.to_string(),
-    //         self.reference.to_string(),
-    //         self.alternative.to_string(),
-    //         self.quality
-    //             .map(|v| v.to_string())
-    //             .unwrap_or(".".to_string()),
-    //         self.filter.to_string(),
-    //         self.infos.to_string(),
-    //     ];
-    //
-    //     if !self.formats.0.is_empty() {
-    //         let (format, values) = self.formats.clone().into();
-    //         columns.push(format);
-    //         columns.push(values);
-    //     }
-    //
-    //     columns.join("\t")
-    //
-    // }
-
-    // pub fn hash_variant(&self) -> Hash128 {
-    //     // Create a new BLAKE3 hasher
-    //     let mut hasher = blake3::Hasher::new();
-    //     // Update the hasher with the fields of the variant
-    //     hasher.update(&self.position.contig.to_ne_bytes()); // Convert position to bytes
-    //     hasher.update(&self.position.position.to_ne_bytes()); // Convert position to bytes
-    //     hasher.update(self.reference.to_string().as_bytes()); // Reference string as bytes
-    //     hasher.update(self.alternative.to_string().as_bytes()); // Alternative string as bytes
-    //
-    //     // Finalize the hash and get the output
-    //     // let hash_output = hasher.finalize();
-    //
-    //     // Convert the first 16 bytes of the hash output to a u128
-    //     // let mut array = [0u8; 16];
-    //     // array.copy_from_slice(&hash_output.as_bytes()[..16]);
-    //
-    //     // Convert to u128
-    //     // u128::from_ne_bytes(array)
-    //     let hash = hasher.finalize();
-    //     Hash128::new(hash.as_bytes()[..16].try_into().unwrap())
-    // }
-
     pub fn alteration_category(&self) -> AlterationCategory {
         match (&self.reference, &self.alternative) {
             (ReferenceAlternative::Nucleotide(_), ReferenceAlternative::Nucleotide(_)) => {