|
|
@@ -8,7 +8,7 @@ use crate::{
|
|
|
commands::{
|
|
|
dorado::{DoradoAlign, DoradoBasecall},
|
|
|
run_many_sbatch,
|
|
|
- samtools::{SamtoolsIndex, SamtoolsMerge, SamtoolsSort, SamtoolsSplit},
|
|
|
+ samtools::{SamtoolsIndex, SamtoolsMerge, SamtoolsMergeMany, SamtoolsSort, SamtoolsSplit},
|
|
|
SlurmRunner,
|
|
|
},
|
|
|
config::Config,
|
|
|
@@ -457,6 +457,13 @@ pub fn import_run(run: &Pod5sRun, config: &Config) -> anyhow::Result<()> {
|
|
|
// remove unsorted chunk
|
|
|
fs::remove_file(&bam)?;
|
|
|
|
|
|
+ let mut index_cmd = SamtoolsIndex {
|
|
|
+ bin: config.align.samtools_bin.clone(),
|
|
|
+ threads: config.align.samtools_view_threads,
|
|
|
+ bam: sorted_bam.to_string_lossy().to_string(),
|
|
|
+ };
|
|
|
+ SlurmRunner::run(&mut index_cmd)?;
|
|
|
+
|
|
|
// replace path in case_bam_map with sorted version
|
|
|
*bam = sorted_bam;
|
|
|
}
|
|
|
@@ -481,6 +488,11 @@ pub fn import_run(run: &Pod5sRun, config: &Config) -> anyhow::Result<()> {
|
|
|
continue;
|
|
|
};
|
|
|
|
|
|
+ if aligned_bams.is_empty() {
|
|
|
+ warn!("Aligned BAM list is empty for case {}", case.case_id);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
let final_bam_path = PathBuf::from(&config.result_dir)
|
|
|
.join(&case.case_id)
|
|
|
.join(&sample_type_dir)
|
|
|
@@ -491,39 +503,106 @@ pub fn import_run(run: &Pod5sRun, config: &Config) -> anyhow::Result<()> {
|
|
|
|
|
|
fs::create_dir_all(final_bam_path.parent().unwrap())?;
|
|
|
|
|
|
- for bam in aligned_bams {
|
|
|
- if final_bam_path.exists() {
|
|
|
- let mut index_cmd = SamtoolsIndex {
|
|
|
- bin: config.align.samtools_bin.clone(),
|
|
|
- threads: config.align.samtools_view_threads,
|
|
|
- bam: bam.to_string_lossy().to_string(),
|
|
|
- };
|
|
|
- SlurmRunner::run(&mut index_cmd)?;
|
|
|
- let mut index_cmd = SamtoolsIndex {
|
|
|
- bin: config.align.samtools_bin.clone(),
|
|
|
- threads: config.align.samtools_view_threads,
|
|
|
- bam: final_bam_path.to_string_lossy().to_string(),
|
|
|
- };
|
|
|
- SlurmRunner::run(&mut index_cmd)?;
|
|
|
-
|
|
|
- // Merge into existing - clean_up() removes source bam
|
|
|
- let mut merge_cmd = SamtoolsMerge::from_config(config, bam, &final_bam_path);
|
|
|
- SlurmRunner::run(&mut merge_cmd)?;
|
|
|
- } else {
|
|
|
- // First BAM becomes the base
|
|
|
- fs::rename(bam, &final_bam_path)?;
|
|
|
-
|
|
|
- // Index the final BAM
|
|
|
- let mut index_cmd = SamtoolsIndex {
|
|
|
- bin: config.align.samtools_bin.clone(),
|
|
|
- threads: config.align.samtools_view_threads,
|
|
|
- bam: final_bam_path.to_string_lossy().to_string(),
|
|
|
- };
|
|
|
- SlurmRunner::run(&mut index_cmd)?;
|
|
|
+ // -----------------------------------------------------------------
|
|
|
+ // 5a) Merge all chunk BAMs for this case into a single per-case BAM
|
|
|
+ // using SamtoolsMergeMany (header from first chunk).
|
|
|
+ // -----------------------------------------------------------------
|
|
|
+
|
|
|
+ let case_merged_bam: PathBuf = if aligned_bams.len() == 1 {
|
|
|
+ // Only one chunk: use it directly
|
|
|
+ aligned_bams[0].clone()
|
|
|
+ } else {
|
|
|
+ let tmp_case_merged = tmp_dir.join(format!(
|
|
|
+ "{}_{}_{}_merged.bam",
|
|
|
+ Uuid::new_v4(),
|
|
|
+ case.case_id,
|
|
|
+ sample_type_dir
|
|
|
+ ));
|
|
|
+
|
|
|
+ info!(
|
|
|
+ " Merging {} chunk BAMs for case {} → {}",
|
|
|
+ aligned_bams.len(),
|
|
|
+ case.case_id,
|
|
|
+ tmp_case_merged.display()
|
|
|
+ );
|
|
|
+
|
|
|
+ let mut merge_many_cmd = SamtoolsMergeMany::from_config(
|
|
|
+ tmp_case_merged.clone(),
|
|
|
+ aligned_bams.clone(),
|
|
|
+ config,
|
|
|
+ );
|
|
|
+ SlurmRunner::run(&mut merge_many_cmd)?;
|
|
|
+
|
|
|
+ // We can safely remove the chunk BAMs now (they were all inputs).
|
|
|
+ for bam in aligned_bams {
|
|
|
+ if bam != &tmp_case_merged {
|
|
|
+ if let Err(e) = fs::remove_file(bam) {
|
|
|
+ warn!(
|
|
|
+ "Failed to remove chunk BAM {} after merge: {e}",
|
|
|
+ bam.display()
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ tmp_case_merged
|
|
|
+ };
|
|
|
+
|
|
|
+ // -----------------------------------------------------------------
|
|
|
+ // 5b) Merge the per-case BAM into the final BAM for this case
|
|
|
+ // using SamtoolsMerge (incremental merge).
|
|
|
+ // -----------------------------------------------------------------
|
|
|
+
|
|
|
+ if final_bam_path.exists() {
|
|
|
+ info!(
|
|
|
+ " Final BAM already exists for case {}, merging into existing: {}",
|
|
|
+ case.case_id,
|
|
|
+ final_bam_path.display()
|
|
|
+ );
|
|
|
+
|
|
|
+ // Index both source (per-case) and destination BAMs
|
|
|
+ let mut index_cmd = SamtoolsIndex {
|
|
|
+ bin: config.align.samtools_bin.clone(),
|
|
|
+ threads: config.align.samtools_view_threads,
|
|
|
+ bam: case_merged_bam.to_string_lossy().to_string(),
|
|
|
+ };
|
|
|
+ SlurmRunner::run(&mut index_cmd)?;
|
|
|
+
|
|
|
+ let mut index_cmd = SamtoolsIndex {
|
|
|
+ bin: config.align.samtools_bin.clone(),
|
|
|
+ threads: config.align.samtools_view_threads,
|
|
|
+ bam: final_bam_path.to_string_lossy().to_string(),
|
|
|
+ };
|
|
|
+ SlurmRunner::run(&mut index_cmd)?;
|
|
|
+
|
|
|
+ // Merge into existing final BAM.
|
|
|
+ // SamtoolsMerge::clean_up() will remove the source BAM.
|
|
|
+ let mut merge_cmd =
|
|
|
+ SamtoolsMerge::from_config(config, &case_merged_bam, &final_bam_path);
|
|
|
+ SlurmRunner::run(&mut merge_cmd)?;
|
|
|
+ } else {
|
|
|
+ info!(
|
|
|
+ " Creating new final BAM for case {} → {}",
|
|
|
+ case.case_id,
|
|
|
+ final_bam_path.display()
|
|
|
+ );
|
|
|
+
|
|
|
+ // First per-case BAM becomes the base final BAM.
|
|
|
+ fs::rename(&case_merged_bam, &final_bam_path)?;
|
|
|
+
|
|
|
+ // Index the new final BAM.
|
|
|
+ let mut index_cmd = SamtoolsIndex {
|
|
|
+ bin: config.align.samtools_bin.clone(),
|
|
|
+ threads: config.align.samtools_view_threads,
|
|
|
+ bam: final_bam_path.to_string_lossy().to_string(),
|
|
|
+ };
|
|
|
+ SlurmRunner::run(&mut index_cmd)?;
|
|
|
}
|
|
|
|
|
|
- // Sort the merged final BAM
|
|
|
+ // -----------------------------------------------------------------
|
|
|
+ // 5c) Sort and index the final BAM
|
|
|
+ // -----------------------------------------------------------------
|
|
|
+
|
|
|
let sorted_tmp = final_bam_path.with_extension("sorted.bam");
|
|
|
|
|
|
info!(
|
|
|
@@ -547,6 +626,63 @@ pub fn import_run(run: &Pod5sRun, config: &Config) -> anyhow::Result<()> {
|
|
|
SlurmRunner::run(&mut index_cmd)?;
|
|
|
|
|
|
info!(" Output: {}", final_bam_path.display());
|
|
|
+
|
|
|
+ // for bam in aligned_bams {
|
|
|
+ // if final_bam_path.exists() {
|
|
|
+ // let mut index_cmd = SamtoolsIndex {
|
|
|
+ // bin: config.align.samtools_bin.clone(),
|
|
|
+ // threads: config.align.samtools_view_threads,
|
|
|
+ // bam: bam.to_string_lossy().to_string(),
|
|
|
+ // };
|
|
|
+ // SlurmRunner::run(&mut index_cmd)?;
|
|
|
+ // let mut index_cmd = SamtoolsIndex {
|
|
|
+ // bin: config.align.samtools_bin.clone(),
|
|
|
+ // threads: config.align.samtools_view_threads,
|
|
|
+ // bam: final_bam_path.to_string_lossy().to_string(),
|
|
|
+ // };
|
|
|
+ // SlurmRunner::run(&mut index_cmd)?;
|
|
|
+ //
|
|
|
+ // // Merge into existing - clean_up() removes source bam
|
|
|
+ // let mut merge_cmd = SamtoolsMerge::from_config(config, bam, &final_bam_path);
|
|
|
+ // SlurmRunner::run(&mut merge_cmd)?;
|
|
|
+ // } else {
|
|
|
+ // // First BAM becomes the base
|
|
|
+ // fs::rename(bam, &final_bam_path)?;
|
|
|
+ //
|
|
|
+ // // Index the final BAM
|
|
|
+ // let mut index_cmd = SamtoolsIndex {
|
|
|
+ // bin: config.align.samtools_bin.clone(),
|
|
|
+ // threads: config.align.samtools_view_threads,
|
|
|
+ // bam: final_bam_path.to_string_lossy().to_string(),
|
|
|
+ // };
|
|
|
+ // SlurmRunner::run(&mut index_cmd)?;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ // Sort the merged final BAM
|
|
|
+ // let sorted_tmp = final_bam_path.with_extension("sorted.bam");
|
|
|
+ //
|
|
|
+ // info!(
|
|
|
+ // " Sorting final BAM for case {} → {}",
|
|
|
+ // case.case_id,
|
|
|
+ // final_bam_path.display()
|
|
|
+ // );
|
|
|
+ //
|
|
|
+ // let mut sort_cmd = SamtoolsSort::from_config(config, &final_bam_path, &sorted_tmp);
|
|
|
+ // SlurmRunner::run(&mut sort_cmd)?;
|
|
|
+ //
|
|
|
+ // // Replace unsorted BAM with sorted BAM
|
|
|
+ // fs::rename(&sorted_tmp, &final_bam_path)?;
|
|
|
+ //
|
|
|
+ // // Index the **sorted** final BAM
|
|
|
+ // let mut index_cmd = SamtoolsIndex {
|
|
|
+ // bin: config.align.samtools_bin.clone(),
|
|
|
+ // threads: config.align.samtools_view_threads,
|
|
|
+ // bam: final_bam_path.to_string_lossy().to_string(),
|
|
|
+ // };
|
|
|
+ // SlurmRunner::run(&mut index_cmd)?;
|
|
|
+ //
|
|
|
+ // info!(" Output: {}", final_bam_path.display());
|
|
|
}
|
|
|
|
|
|
if let Some(d) = tmp_split_dir {
|