config.rs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290
  1. use log::{info, warn};
  2. use serde::{Deserialize, Serialize};
  3. use std::fs;
  4. use std::path::{Path, PathBuf};
  5. const CONFIG_TEMPLATE: &str = include_str!("../pandora-config.example.toml");
  6. #[derive(Debug, Clone, Serialize, Deserialize)]
  7. /// Global configuration for the Pandora somatic pipeline.
  8. ///
  9. /// Loaded from `~/.local/share/pandora/pandora-config.toml` (see [`Config::config_path`]).
  10. /// Most fields are path templates that can contain placeholders such as:
  11. /// `{result_dir}`, `{id}`, `{time}`, `{reference_name}`, `{haplotagged_bam_tag_name}`, `{output_dir}`.
  12. pub struct Config {
  13. // === General filesystem layout / I/O ===
  14. /// Root directory where all results will be written.
  15. pub result_dir: String,
  16. /// Temporary directory.
  17. pub tmp_dir: String,
  18. /// Run cache directory.
  19. pub run_cache_dir: String,
  20. /// Runner can slurm
  21. pub slurm_runner: bool,
  22. /// Slurm max parallel jobs
  23. pub slurm_max_par: u8,
  24. /// Software threads
  25. pub threads: u8,
  26. /// Singularity/Apptainer bin
  27. pub singularity_bin: String,
  28. /// Path to the `conda.sh` activation script (used to activate envs before running tools).
  29. pub conda_sh: String,
  30. // === Alignment / BAM handling ===
  31. /// Configuration for Dorado + samtools alignment pipeline.
  32. pub align: AlignConfig,
  33. /// Minimum MAPQ for reads to be kept during BAM filtering.
  34. pub bam_min_mapq: u8,
  35. /// Number of threads for hts BAM reader
  36. pub bam_n_threads: u8,
  37. /// Number of reads sampled when estimating BAM composition (e.g. tumor contamination).
  38. pub bam_composition_sample_size: u32,
  39. // === Reference genome and annotations ===
  40. /// Path to the reference FASTA used throughout the pipeline.
  41. pub reference: String,
  42. /// Short name for the reference (e.g. "hs1"), used in filenames.
  43. pub reference_name: String,
  44. /// Pseudoautosomal regions (PARs) BED file.
  45. pub pseudoautosomal_regions_bed: String,
  46. /// Path to the sequence dictionary (`.dict`) for the reference.
  47. pub dict_file: String,
  48. /// Path to the RefSeq GFF3 annotation, sorted and indexed.
  49. pub refseq_gff: String,
  50. pub refseq_gtf: String,
  51. /// dbSNP vcf.gz file (should be indexed)
  52. pub db_snp: String,
  53. /// CoLoRSdb jasmine (should be indexed, tbi)
  54. pub colors_db: String,
  55. pub colors_db_smallvar: String,
  56. /// BED with genes on the 4th column
  57. pub genes_bed: String,
  58. /// Cytobands BED file
  59. pub cytobands_bed: String,
  60. /// Chromosome alias file
  61. pub chromosomes_alias: String,
  62. /// BED template used to mask low-quality or filtered regions.
  63. ///
  64. /// Placeholders:
  65. /// - `{result_dir}`: global result directory
  66. /// - `{id}`: case identifier
  67. pub mask_bed: String,
  68. /// Panels of interest (name, BED path).
  69. pub panels: Vec<(String, String)>,
  70. /// Repeats bed file
  71. pub repeats_bed: String,
  72. // === Sample naming conventions ===
  73. /// Label used for the tumor sample in directory and file names (e.g. "diag").
  74. pub tumoral_name: String,
  75. /// Label used for the normal sample (e.g. "mrd").
  76. pub normal_name: String,
  77. /// BAM tag name used for haplotagged reads (e.g. "HP").
  78. pub haplotagged_bam_tag_name: String,
  79. // === Coverage counting (somatic-scan) ===
  80. /// Name of the subdirectory (under each sample dir) where count files are stored.
  81. pub count_dir_name: String,
  82. /// Bin size (bp) for count files.
  83. pub count_bin_size: u32,
  84. /// Number of chunks used to split chromosomes for counting.
  85. pub count_n_chunks: u32,
  86. /// Whether to force recomputation of coverage / counting even if outputs already exist.
  87. pub somatic_scan_force: bool,
  88. // === Somatic pipeline global options ===
  89. /// Whether to force recomputation of the whole somatic pipeline.
  90. pub somatic_pipe_force: bool,
  91. /// Default number of threads for most heavy tools (DeepVariant, Savana, etc.).
  92. pub somatic_pipe_threads: u8,
  93. /// Path template to the per-case somatic pipeline statistics directory.
  94. ///
  95. /// Placeholders: `{result_dir}`, `{id}`.
  96. pub somatic_pipe_stats: String,
  97. // === Basic somatic filtering / QC thresholds ===
  98. /// Minimum depth in the constitutional sample to consider a site evaluable.
  99. pub somatic_min_constit_depth: u16,
  100. /// Maximum allowed ALT count in the constitutional sample for a somatic call.
  101. pub somatic_max_alt_constit: u16,
  102. /// Window size (bp) used when computing sequence entropy around variants.
  103. pub entropy_seq_len: usize,
  104. /// Minimum Shannon entropy threshold for keeping a variant.
  105. pub min_shannon_entropy: f64,
  106. /// Minimum dbSNP population frequency (max across studies) to consider a variant a known
  107. /// polymorphism for the dbSNP + constitutional-alt filter.
  108. pub db_snp_min_freq: f32,
  109. /// Maximum depth considered "low quality" for certain filters.
  110. pub max_depth_low_quality: u32,
  111. /// Minimum depth considered "high quality" for certain filters.
  112. pub min_high_quality_depth: u32,
  113. /// Minimum number of callers supporting a variant for it to be kept.
  114. pub min_n_callers: u8,
  115. // === DeepVariant configuration ===
  116. /// Template for the DeepVariant output directory (solo and normal/tumor runs).
  117. ///
  118. /// Placeholders: `{result_dir}`, `{id}`, `{time}`.
  119. pub deepvariant_output_dir: String,
  120. /// Number of threads to use for DeepVariant.
  121. pub deepvariant_threads: u8,
  122. /// DeepVariant singularity image path
  123. pub deepvariant_image: String,
  124. /// DeepVariant model type (e.g. "ONT_R104").
  125. pub deepvariant_model_type: String,
  126. /// Force DeepVariant recomputation even if outputs already exist.
  127. pub deepvariant_force: bool,
  128. // === DeepSomatic configuration ===
  129. /// Template for the DeepSomatic output directory.
  130. ///
  131. /// Placeholders: `{result_dir}`, `{id}`, `{time}`.
  132. pub deepsomatic_output_dir: String,
  133. /// Number of threads for DeepSomatic.
  134. pub deepsomatic_threads: u8,
  135. /// DeepSomatic singularity image path
  136. pub deepsomatic_image: String,
  137. /// DeepSomatic model type (e.g. "ONT").
  138. pub deepsomatic_model_type: String,
  139. /// Force DeepSomatic recomputation.
  140. pub deepsomatic_force: bool,
  141. // === ClairS configuration ===
  142. /// Number of threads for ClairS.
  143. pub clairs_threads: u8,
  144. /// Path to ClairS singularity image.
  145. pub clairs_image: String,
  146. /// Force ClairS recomputation.
  147. pub clairs_force: bool,
  148. /// Keep per-part directories after chunked ClairS merging (default: false).
  149. pub clairs_keep_parts: bool,
  150. /// Platform preset for ClairS (e.g. "ont_r10_dorado_sup_5khz_ssrs").
  151. pub clairs_platform: String,
  152. /// Template for ClairS output directory (`{result_dir}`, `{id}`).
  153. pub clairs_output_dir: String,
  154. // === GATK configuration ===
  155. /// Path to the GATK container image (Singularity/Apptainer .sif, or a docker:// URI
  156. /// if you pull at runtime).
  157. ///
  158. /// Examples:
  159. /// - "/containers/gatk_4.6.0.0.sif"
  160. /// - "docker://broadinstitute/gatk:latest"
  161. pub gatk_image: String,
  162. /// Path to a BED file restricting analysis to target regions (0-based, half-open).
  163. /// Must match contig naming of the reference/BAMs (e.g. "chr9" vs "9").
  164. ///
  165. /// Used for targeted calling (e.g. Mutect2 `-L` or region chunking).
  166. pub gatk_bed_path: String,
  167. /// Local single-run CPU threads (non-Slurm execution).
  168. /// Used for full-run Mutect2 or other GATK tools.
  169. /// Typically forwarded to:
  170. /// - `--native-pair-hmm-threads`
  171. /// - `--reader-threads`
  172. /// Should match available cores on the node.
  173. pub gatk_threads: usize, // e.g. 32
  174. /// Local single-run memory limit in GB.
  175. /// Used to size Java heap:
  176. /// `--java-options "-Xmx{mem}g"`
  177. /// Should leave headroom for native memory (PairHMM, buffers).
  178. pub gatk_mem_gb: u32, // e.g. 120
  179. /// Per-chunk CPU threads when running chunked under Slurm.
  180. /// Applies to each parallel job independently.
  181. pub gatk_slurm_threads: usize, // e.g. 8
  182. /// Per-chunk memory (GB) when running under Slurm.
  183. /// Used both for scheduler request and Java heap sizing per chunk.
  184. /// Must be sufficient for interval-restricted Mutect2.
  185. pub gatk_slurm_mem_gb: u32, // e.g. 32
  186. /// If true, force re-run of GATK steps by removing or ignoring existing outputs.
  187. pub gatk_force: bool,
  188. /// Template for GATK output directory (`{result_dir}`, `{id}`).
  189. pub gatk_output_dir: String,
  190. /// GATK passed VCF
  191. pub gatk_passed_vcf: String,
  192. // === Savana configuration ===
  193. /// Savana binary name or full path.
  194. pub savana_bin: String,
  195. /// Number of threads for Savana.
  196. pub savana_threads: u8,
  197. /// RAM capacity used for running Savana with slurm.
  198. pub savana_mem: u8,
  199. /// Template for Savana output directory (`{result_dir}`, `{id}`).
  200. pub savana_output_dir: String,
  201. /// Template for Savana copy number file.
  202. ///
  203. /// Placeholders: `{output_dir}`, `{id}`, `{reference_name}`, `{haplotagged_bam_tag_name}`.
  204. pub savana_copy_number: String,
  205. /// Template for Savana raw read counts file.
  206. ///
  207. /// Same placeholders as [`Config::savana_copy_number`].
  208. pub savana_read_counts: String,
  209. /// Template for Savana passed VCF output (`{output_dir}`, `{id}`).
  210. pub savana_passed_vcf: String,
  211. /// Force Savana recomputation.
  212. pub savana_force: bool,
  213. /// Template for constitutional phased VCF (`{result_dir}`, `{id}`).
  214. pub germline_phased_vcf: String,
  215. // === CoRAL ===
  216. /// Number of CPU threads for the CoRAL reconstruction job.
  217. ///
  218. /// CoRAL is CPU-bound during breakpoint graph construction and quadratic
  219. /// programming cycle extraction. 8–16 threads is sufficient for most
  220. /// focal amplification cases; increase for highly complex ecDNA with
  221. /// many amplicons.
  222. ///
  223. /// # TOML
  224. /// ```toml
  225. /// coral_threads = 16
  226. /// ```
  227. pub coral_threads: u8,
  228. pub coral_dir: String,
  229. /// Memory allocation for the CoRAL SLURM job (e.g. `"32G"`).
  230. ///
  231. /// Memory usage scales with amplicon complexity and BAM depth.
  232. /// 32G is sufficient for typical WGS at 30–60×; increase to 64G
  233. /// for highly rearranged genomes (chromothripsis, high ecDNA copy number).
  234. ///
  235. /// # TOML
  236. /// ```toml
  237. /// coral_slurm_mem = "32G"
  238. /// ```
  239. pub coral_slurm_mem: String,
  240. /// SLURM partition to use for CoRAL jobs.
  241. ///
  242. /// CoRAL requires only CPU — do not submit to a GPU partition.
  243. /// Use the same partition as other CPU-bound callers (e.g. Severus, NanomonSV).
  244. ///
  245. /// # TOML
  246. /// ```toml
  247. /// coral_slurm_partition = "cpuq"
  248. /// ```
  249. pub coral_slurm_partition: String,
  250. /// Minimum copy number gain threshold for a segment to be considered
  251. /// a focal amplification seed (CoRAL `--gain`).
  252. ///
  253. /// CoRAL applies this threshold to the raw absolute CN values from the
  254. /// cn_segs BED — do NOT pre-correct for purity or ploidy, as this may
  255. /// cause entire chromosome arms to exceed the threshold in aneuploid tumours.
  256. ///
  257. /// Default in CoRAL is 6.0 (diploid assumption). For hyperdiploid tumours
  258. /// (e.g. hyperploid ALL, CML blast crisis) consider lowering to 4.0–5.0.
  259. ///
  260. /// # TOML
  261. /// ```toml
  262. /// coral_seed_gain = 6.0
  263. /// ```
  264. pub coral_seed_gain: f64,
  265. /// Minimum size in base pairs for a CN segment to qualify as a seed
  266. /// (CoRAL `--min-seed-size`).
  267. ///
  268. /// Segments below this size are discarded even if they exceed `coral_seed_gain`.
  269. /// Two merged proximal segments (see `coral_max_seg_gap`) are evaluated
  270. /// against this threshold as a single combined interval.
  271. ///
  272. /// Default in CoRAL is 100000 (100 kb). Reducing this risks including
  273. /// artefactual short high-copy segments; increasing it misses small focal
  274. /// amplifications (e.g. narrow EGFR or MYC peaks).
  275. ///
  276. /// # TOML
  277. /// ```toml
  278. /// coral_min_seed_size = 100000
  279. /// ```
  280. pub coral_min_seed_size: u32,
  281. /// Maximum gap in base pairs between two proximal CN segments to allow
  282. /// merging into a single seed candidate (CoRAL `--max-seg-gap`).
  283. ///
  284. /// If two amplified segments are separated by a gap smaller than this value,
  285. /// they are merged before the `coral_min_seed_size` filter is applied.
  286. /// This handles cases where a single focal amplicon is split by a low-coverage
  287. /// or diploid bin.
  288. ///
  289. /// Default in CoRAL is 300000 (300 kb). For haematological cancers with
  290. /// compact focal amplifications (e.g. NUP214::ABL1, ABL1 amplification in
  291. /// CML blast crisis) a tighter value such as 100000 reduces spurious merging
  292. /// of adjacent independent amplicons.
  293. ///
  294. /// # TOML
  295. /// ```toml
  296. /// coral_max_seg_gap = 100000
  297. /// ```
  298. pub coral_max_seg_gap: u32,
  299. // === Severus configuration ===
  300. /// Path to Severus main script (`severus.py`).
  301. pub severus_bin: String,
  302. /// Force Severus recomputation.
  303. pub severus_force: bool,
  304. /// Number of threads for Severus.
  305. pub severus_threads: u8,
  306. /// VNTRs BED file for Severus.
  307. pub vntrs_bed: String,
  308. /// Path to Severus PoN file (TSV or VCF).
  309. pub severus_pon: String,
  310. /// Template for Severus tumor/normal (paired) output directory.
  311. ///
  312. /// Placeholders: `{result_dir}`, `{id}`.
  313. pub severus_output_dir: String,
  314. /// Template for Severus solo output directory.
  315. ///
  316. /// Placeholders: `{result_dir}`, `{id}`, `{time}`.
  317. pub severus_solo_output_dir: String,
  318. // === MARLIN ===
  319. pub marlin_bed: String,
  320. // === Echtvar ===
  321. pub echtvar_bin: String,
  322. pub echtvar_sources: Vec<String>,
  323. // === Bcftools configuration ===
  324. /// Path to Bcftools binary.
  325. pub bcftools_bin: String,
  326. /// Number of threads for Bcftools.
  327. pub bcftools_threads: u8,
  328. // === Longphase configuration ===
  329. /// Path to longphase binary.
  330. pub longphase_bin: String,
  331. /// Number of threads for longphase.
  332. pub longphase_threads: u8,
  333. /// Number of threads for longphase modcall step.
  334. pub longphase_modcall_threads: u8,
  335. /// Force longphase recomputation (haplotagging/phasing).
  336. pub longphase_force: bool,
  337. /// Template for longphase modcall VCF.
  338. ///
  339. /// Placeholders: `{result_dir}`, `{id}`, `{time}`.
  340. pub longphase_modcall_vcf: String,
  341. // === Modkit configuration ===
  342. /// Path to modkit binary.
  343. pub modkit_bin: String,
  344. /// Number of threads for `modkit summary`.
  345. pub modkit_summary_threads: u8,
  346. /// Template for modkit summary output file.
  347. ///
  348. /// Placeholders: `{result_dir}`, `{id}`, `{time}`.
  349. pub modkit_summary_file: String,
  350. // === Nanomonsv configuration ===
  351. /// Path to nanomonsv binary.
  352. pub nanomonsv_bin: String,
  353. /// Template for paired nanomonsv output directory (`{result_dir}`, `{id}`, `{time}`).
  354. pub nanomonsv_output_dir: String,
  355. /// Force nanomonsv recomputation.
  356. pub nanomonsv_force: bool,
  357. /// Number of threads for nanomonsv.
  358. pub nanomonsv_threads: u8,
  359. /// Template for paired nanomonsv passed VCF (`{output_dir}`, `{id}`).
  360. pub nanomonsv_passed_vcf: String,
  361. /// Template for solo nanomonsv output directory.
  362. ///
  363. /// Placeholders: `{result_dir}`, `{id}`, `{time}`.
  364. pub nanomonsv_solo_output_dir: String,
  365. /// Template for solo nanomonsv passed VCF (`{output_dir}`, `{id}`, `{time}`).
  366. pub nanomonsv_solo_passed_vcf: String,
  367. pub nanomonsv_simple_repeat_bed: String,
  368. pub nanomonsv_line1_bed: String,
  369. // === Straglr configuration ===
  370. /// Path to Straglr executable.
  371. pub straglr_bin: String,
  372. /// Path to STR loci BED file for Straglr.
  373. pub straglr_loci_bed: String,
  374. /// Size of reported difference between normal and tumoral
  375. pub straglr_min_size_diff: u32,
  376. /// Minimum CN of reported difference between normal and tumoral
  377. pub straglr_min_support_diff: u32,
  378. /// Minimum read support for STR genotyping.
  379. pub straglr_min_support: u32,
  380. /// Minimum cluster size for STR detection.
  381. pub straglr_min_cluster_size: u32,
  382. /// Whether to genotype in size mode.
  383. pub straglr_genotype_in_size: bool,
  384. /// Template for paired Straglr output directory.
  385. ///
  386. /// Placeholders: `{result_dir}`, `{id}`.
  387. pub straglr_output_dir: String,
  388. /// Template for solo Straglr output directory.
  389. ///
  390. /// Placeholders: `{result_dir}`, `{id}`, `{time}`.
  391. pub straglr_solo_output_dir: String,
  392. /// Force Straglr recomputation.
  393. pub straglr_force: bool,
  394. // === PromethION runs / metadata ===
  395. /// Directory containing metadata about PromethION runs.
  396. pub promethion_runs_metadata_dir: String,
  397. /// JSON file describing PromethION runs and flowcell IDs.
  398. pub promethion_runs_input: String,
  399. // === VEP ===
  400. /// Path to VEP singularity image
  401. pub vep_image: String,
  402. /// Path to the VEP cache directory
  403. pub vep_cache_dir: String,
  404. /// Path to VEP sorted GFF
  405. pub vep_gff: String,
  406. // === Flye ===
  407. /// "python_bin_path flye_bin_path" ex.: "/usr/bin/python /home/t_steimle/somatic_pipe_tools/Flye/bin/flye"
  408. pub flye_bin: String,
  409. /// Flye threads
  410. pub flye_threads: u8,
  411. /// Slurm max mem
  412. pub flye_slurm_mem: String,
  413. pub minimap2_bin: String,
  414. pub minimap2_threads: u8,
  415. pub minimap2_slurm_mem: String,
  416. pub medaka_env: String,
  417. pub medaka_consensus_bin: String,
  418. pub medaka_threads: u8,
  419. pub medaka_slurm_mem: String,
  420. pub medaka_model: String,
  421. pub wtdbg2_bin: String,
  422. pub wtdbg2_threads: u8,
  423. pub wtdbg2_slurm_mem: String,
  424. // === longcallD configuration ===
  425. /// Template for the longcallD output directory (solo and normal/tumor runs).
  426. ///
  427. /// Placeholders: `{result_dir}`, `{id}`, `{time}`.
  428. pub longcalld_output_dir: String,
  429. pub longcalld_bin: String,
  430. pub longcalld_threads: u8,
  431. pub longcalld_slurm_mem: String,
  432. }
  433. #[derive(Debug, Clone, Serialize, Deserialize)]
  434. /// Configuration for basecalling and alignment using Dorado and samtools.
  435. pub struct AlignConfig {
  436. /// Path to Dorado binary.
  437. pub dorado_bin: String,
  438. /// Arguments passed to `dorado basecaller` (e.g. devices and model name).
  439. pub dorado_basecall_arg: String,
  440. /// Should dorado re-align after demux ?
  441. pub dorado_should_realign: bool,
  442. /// Dorado aligner threads number
  443. pub dorado_aligner_threads: u8,
  444. /// Reference FASTA used for alignment.
  445. pub ref_fa: String,
  446. /// Minimap2 index (`.mmi`) used by Dorado or downstream tools.
  447. pub ref_mmi: String,
  448. /// Path to Samtools binary.
  449. pub samtools_bin: String,
  450. /// Number of threads given to `samtools view`.
  451. pub samtools_view_threads: u8,
  452. /// Number of threads given to `samtools sort`.
  453. pub samtools_sort_threads: u8,
  454. /// Number of threads given to `samtools merge`.
  455. pub samtools_merge_threads: u8,
  456. /// Number of threads given to `samtools split`.
  457. pub samtools_split_threads: u8,
  458. }
  459. // Here comes names that can't be changed from output of tools
  460. lazy_static! {
  461. /// Template name for DeepVariant VCF outputs.
  462. static ref DEEPVARIANT_OUTPUT_NAME: &'static str = "{id}_{time}_DeepVariant.vcf.gz";
  463. /// ClairS main SNP/indel VCF name.
  464. static ref CLAIRS_OUTPUT_NAME: &'static str = "output.vcf.gz";
  465. /// ClairS indel-only VCF name.
  466. static ref CLAIRS_OUTPUT_INDELS_NAME: &'static str = "indel.vcf.gz";
  467. /// ClairS germline normal VCF name.
  468. static ref CLAIRS_GERMLINE_NORMAL: &'static str = "clair3_normal_germline_output.vcf.gz";
  469. /// ClairS germline tumor VCF name.
  470. static ref CLAIRS_GERMLINE_TUMOR: &'static str = "clair3_tumor_germline_output.vcf.gz";
  471. }
  472. // impl Default for AlignConfig {
  473. // fn default() -> Self {
  474. // Self {
  475. // dorado_bin: "/data/tools/dorado-1.1.1-linux-x64/bin/dorado".to_string(),
  476. // dorado_basecall_arg: "-x 'cuda:0,1,2,3' sup,5mC_5hmC".to_string(),
  477. // ref_fa: "/data/ref/hs1/chm13v2.0.fa".to_string(),
  478. // ref_mmi: "/data/ref/chm13v2.0.mmi".to_string(),
  479. // samtools_view_threads: 20,
  480. // samtools_sort_threads: 50,
  481. // }
  482. // }
  483. // }
  484. //
  485. impl Config {
  486. /// Returns the config file path, e.g.:
  487. /// `~/.local/share/pandora/pandora-config.toml`.
  488. pub fn config_path() -> PathBuf {
  489. let mut path = directories::ProjectDirs::from("", "", "pandora")
  490. .expect("Could not determine project directory")
  491. .config_dir()
  492. .to_path_buf();
  493. path.push("pandora-config.toml");
  494. path
  495. }
  496. /// Install the commented template config on disk **if it does not exist yet**.
  497. ///
  498. /// This writes `CONFIG_TEMPLATE` verbatim so comments are preserved.
  499. fn write_template_if_missing() -> Result<(), Box<dyn std::error::Error>> {
  500. let path = Self::config_path();
  501. if path.exists() {
  502. // Do not touch an existing user config.
  503. return Ok(());
  504. }
  505. if let Some(parent) = path.parent() {
  506. fs::create_dir_all(parent)?;
  507. }
  508. fs::write(&path, CONFIG_TEMPLATE)?;
  509. info!("Config template written to: {}", path.display());
  510. Ok(())
  511. }
  512. /// “Save” configuration.
  513. ///
  514. /// In this model, we do **not** overwrite the user config (to preserve comments).
  515. /// `save()` only ensures the template exists on disk on first run.
  516. pub fn save(&self) -> Result<(), Box<dyn std::error::Error>> {
  517. Self::write_template_if_missing()
  518. }
  519. pub fn from_path(path: impl AsRef<Path>) -> Self {
  520. let path = path.as_ref().to_path_buf();
  521. // First, ensure there is at least a file on disk (template on first run).
  522. if let Err(e) = Self::write_template_if_missing() {
  523. warn!(
  524. "Warning: failed to ensure config template at {}: {}",
  525. path.display(),
  526. e
  527. );
  528. }
  529. // Try to load and parse the user config file.
  530. match fs::read_to_string(&path) {
  531. Ok(content) => match toml::from_str::<Config>(&content) {
  532. Ok(cfg) => cfg,
  533. Err(e) => {
  534. warn!(
  535. "Warning: failed to parse user config {}: {}. Falling back to embedded template.",
  536. path.display(),
  537. e
  538. );
  539. // Fallback: parse the embedded template.
  540. toml::from_str::<Config>(CONFIG_TEMPLATE)
  541. .expect("embedded config template is invalid")
  542. }
  543. },
  544. Err(e) => {
  545. warn!(
  546. "Warning: failed to read user config {}: {}. Falling back to embedded template.",
  547. path.display(),
  548. e
  549. );
  550. toml::from_str::<Config>(CONFIG_TEMPLATE)
  551. .expect("embedded config template is invalid")
  552. }
  553. }
  554. }
  555. /// Returns `<result_dir>/<id>/<tumoral_name>`.
  556. #[inline]
  557. pub fn tumoral_dir(&self, id: &str) -> String {
  558. format!("{}/{}/{}", self.result_dir, id, self.tumoral_name)
  559. }
  560. /// Returns `<result_dir>/<id>/<normal_name>`.
  561. #[inline]
  562. pub fn normal_dir(&self, id: &str) -> String {
  563. format!("{}/{}/{}", self.result_dir, id, self.normal_name)
  564. }
  565. /// Returns the directory for a "solo" run (timepoint or tag), i.e. `<result_dir>/<id>/<time>`.
  566. #[inline]
  567. pub fn solo_dir(&self, id: &str, time: &str) -> String {
  568. format!("{}/{}/{}", self.result_dir, id, time)
  569. }
  570. /// BAM for a solo run: `<solo_dir>/<id>_<time>_<reference_name>.bam`.
  571. pub fn solo_bam(&self, id: &str, time: &str) -> String {
  572. format!(
  573. "{}/{}_{}_{}.bam",
  574. self.solo_dir(id, time),
  575. id,
  576. time,
  577. self.reference_name,
  578. )
  579. }
  580. /// JSON sidecar for the solo BAM.
  581. pub fn solo_bam_info_json(&self, id: &str, time: &str) -> String {
  582. format!(
  583. "{}/{}_{}_{}_info.json",
  584. self.solo_dir(id, time),
  585. id,
  586. time,
  587. self.reference_name,
  588. )
  589. }
  590. /// Tumor BAM path: `<tumoral_dir>/<id>_<tumoral_name>_<reference_name>.bam`.
  591. pub fn tumoral_bam(&self, id: &str) -> String {
  592. format!(
  593. "{}/{}_{}_{}.bam",
  594. self.tumoral_dir(id),
  595. id,
  596. self.tumoral_name,
  597. self.reference_name,
  598. )
  599. }
  600. /// Normal BAM path: `<normal_dir>/<id>_<normal_name>_<reference_name>.bam`.
  601. pub fn normal_bam(&self, id: &str) -> String {
  602. format!(
  603. "{}/{}_{}_{}.bam",
  604. self.normal_dir(id),
  605. id,
  606. self.normal_name,
  607. self.reference_name,
  608. )
  609. }
  610. /// Tumor haplotagged BAM.
  611. pub fn solo_haplotagged_bam(&self, id: &str, time: &str) -> String {
  612. format!(
  613. "{}/{}_{}_{}_{}.bam",
  614. self.solo_dir(id, time),
  615. id,
  616. time,
  617. self.reference_name,
  618. self.haplotagged_bam_tag_name
  619. )
  620. }
  621. /// Tumor haplotagged BAM.
  622. pub fn tumoral_haplotagged_bam(&self, id: &str) -> String {
  623. format!(
  624. "{}/{}_{}_{}_{}.bam",
  625. self.tumoral_dir(id),
  626. id,
  627. self.tumoral_name,
  628. self.reference_name,
  629. self.haplotagged_bam_tag_name
  630. )
  631. }
  632. /// Normal haplotagged BAM.
  633. pub fn normal_haplotagged_bam(&self, id: &str) -> String {
  634. format!(
  635. "{}/{}_{}_{}_{}.bam",
  636. self.normal_dir(id),
  637. id,
  638. self.normal_name,
  639. self.reference_name,
  640. self.haplotagged_bam_tag_name
  641. )
  642. }
  643. /// Normal haplotagged BAM.
  644. pub fn panel_bam(&self, id: &str) -> String {
  645. format!(
  646. "{}/panel/{}_panel_{}.bam",
  647. self.tumoral_dir(id),
  648. id,
  649. self.reference_name,
  650. )
  651. }
  652. pub fn dir_count(&self, id: &str, time: &str) -> String {
  653. format!("{}/{}", self.solo_dir(id, time), self.count_dir_name)
  654. }
  655. /// Normal count directory: `<normal_dir>/<count_dir_name>`.
  656. pub fn normal_dir_count(&self, id: &str) -> String {
  657. format!("{}/{}", self.normal_dir(id), self.count_dir_name)
  658. }
  659. /// Tumor count directory: `<tumoral_dir>/<count_dir_name>`.
  660. pub fn tumoral_dir_count(&self, id: &str) -> String {
  661. format!("{}/{}", self.tumoral_dir(id), self.count_dir_name)
  662. }
  663. /// Mask BED path with `{result_dir}` and `{id}` expanded.
  664. pub fn mask_bed(&self, id: &str) -> String {
  665. self.mask_bed
  666. .replace("{result_dir}", &self.result_dir)
  667. .replace("{id}", id)
  668. }
  669. /// Germline phased VCF with `{result_dir}` and `{id}` expanded.
  670. pub fn germline_phased_vcf(&self, id: &str) -> String {
  671. self.germline_phased_vcf
  672. .replace("{result_dir}", &self.result_dir)
  673. .replace("{id}", id)
  674. }
  675. /// Somatic pipeline stats directory with `{result_dir}` and `{id}` expanded.
  676. pub fn somatic_pipe_stats(&self, id: &str) -> String {
  677. self.somatic_pipe_stats
  678. .replace("{result_dir}", &self.result_dir)
  679. .replace("{id}", id)
  680. }
  681. /// DeepVariant output directory for a given run (`{result_dir}`, `{id}`, `{time}`).
  682. pub fn deepvariant_output_dir(&self, id: &str, time: &str) -> String {
  683. self.deepvariant_output_dir
  684. .replace("{result_dir}", &self.result_dir)
  685. .replace("{id}", id)
  686. .replace("{time}", time)
  687. }
  688. /// DeepVariant solo VCF (raw) for `<id>, <time>`.
  689. pub fn deepvariant_solo_output_vcf(&self, id: &str, time: &str) -> String {
  690. format!(
  691. "{}/{}",
  692. self.deepvariant_output_dir(id, time),
  693. *DEEPVARIANT_OUTPUT_NAME
  694. )
  695. .replace("{id}", id)
  696. .replace("{time}", time)
  697. }
  698. /// DeepVariant output directory for the normal sample.
  699. pub fn deepvariant_normal_output_dir(&self, id: &str) -> String {
  700. self.deepvariant_output_dir(id, &self.normal_name)
  701. }
  702. /// DeepVariant "tumoral output dir" (as in your original code – note: this actually returns the *PASSED VCF* path).
  703. pub fn deepvariant_tumoral_output_dir(&self, id: &str) -> String {
  704. self.deepvariant_solo_passed_vcf(id, &self.tumoral_name)
  705. }
  706. /// DeepVariant solo *PASSED* VCF for `<id>, <time>`.
  707. pub fn deepvariant_solo_passed_vcf(&self, id: &str, time: &str) -> String {
  708. format!(
  709. "{}/{}_{}_DeepVariant_PASSED.vcf.gz",
  710. self.deepvariant_output_dir(id, time),
  711. id,
  712. time
  713. )
  714. }
  715. /// DeepVariant *PASSED* VCF for the normal sample.
  716. pub fn deepvariant_normal_passed_vcf(&self, id: &str) -> String {
  717. self.deepvariant_solo_passed_vcf(id, &self.normal_name)
  718. }
  719. /// DeepVariant *PASSED* VCF for the tumor sample.
  720. pub fn deepvariant_tumoral_passed_vcf(&self, id: &str) -> String {
  721. self.deepvariant_solo_passed_vcf(id, &self.tumoral_name)
  722. }
  723. /// DeepSomatic output directory (uses `{time} = tumoral_name`).
  724. pub fn deepsomatic_output_dir(&self, id: &str) -> String {
  725. self.deepsomatic_output_dir
  726. .replace("{result_dir}", &self.result_dir)
  727. .replace("{id}", id)
  728. .replace("{time}", &self.tumoral_name)
  729. }
  730. /// DeepSomatic raw VCF.
  731. pub fn deepsomatic_output_vcf(&self, id: &str) -> String {
  732. format!(
  733. "{}/{}_{}_DeepSomatic.vcf.gz",
  734. self.deepsomatic_output_dir(id),
  735. id,
  736. self.tumoral_name
  737. )
  738. }
  739. /// DeepSomatic *PASSED* VCF.
  740. pub fn deepsomatic_passed_vcf(&self, id: &str) -> String {
  741. format!(
  742. "{}/{}_{}_DeepSomatic_PASSED.vcf.gz",
  743. self.deepsomatic_output_dir(id),
  744. id,
  745. self.tumoral_name
  746. )
  747. }
  748. /// ClairS output directory (`{result_dir}`, `{id}`).
  749. pub fn clairs_output_dir(&self, id: &str) -> String {
  750. self.clairs_output_dir
  751. .replace("{result_dir}", &self.result_dir)
  752. .replace("{id}", id)
  753. }
  754. /// ClairS main SNP/indel VCFs (standard + indel-only).
  755. pub fn clairs_output_vcfs(&self, id: &str) -> (String, String) {
  756. let dir = self.clairs_output_dir(id);
  757. (
  758. format!("{dir}/{}", *CLAIRS_OUTPUT_NAME),
  759. format!("{dir}/{}", *CLAIRS_OUTPUT_INDELS_NAME),
  760. )
  761. }
  762. /// ClairS somatic *PASSED* VCF.
  763. pub fn clairs_passed_vcf(&self, id: &str) -> String {
  764. format!(
  765. "{}/{}_{}_clairs_PASSED.vcf.gz",
  766. self.clairs_output_dir(id),
  767. id,
  768. self.tumoral_name
  769. )
  770. }
  771. /// ClairS germline normal VCF.
  772. pub fn clairs_germline_normal_vcf(&self, id: &str) -> String {
  773. let dir = self.clairs_output_dir(id);
  774. format!("{dir}/{}", *CLAIRS_GERMLINE_NORMAL)
  775. }
  776. /// ClairS germline tumor VCF.
  777. pub fn clairs_germline_tumor_vcf(&self, id: &str) -> String {
  778. let dir = self.clairs_output_dir(id);
  779. format!("{dir}/{}", *CLAIRS_GERMLINE_TUMOR)
  780. }
  781. /// Consolidated germline *PASSED* VCF from ClairS.
  782. pub fn clairs_germline_passed_vcf(&self, id: &str) -> String {
  783. let dir = self.clairs_output_dir(id);
  784. format!("{dir}/{id}_diag_clair3-germline_PASSED.vcf.gz")
  785. }
  786. /// gatk_output_dir = "{result_dir}/{id}/{tumoral_name}/GATK"
  787. pub fn gatk_output_dir(&self, id: &str) -> String {
  788. self.gatk_output_dir
  789. .replace("{result_dir}", &self.result_dir)
  790. .replace("{id}", id)
  791. .replace("{tumoral_name}", &self.tumoral_name)
  792. }
  793. /// gatk_passed_vcf = "{output_dir}/{id}_{tumoral_name}_{reference_name}_GATK_PASSED.vcf.gz"
  794. pub fn gatk_passed_vcf(&self, id: &str) -> String {
  795. self.gatk_passed_vcf
  796. .replace("{output_dir}", &self.gatk_output_dir(id))
  797. .replace("{id}", id)
  798. .replace("{tumoral_name}", &self.tumoral_name)
  799. .replace("{reference_name}", &self.reference_name)
  800. }
  801. /// Paired nanomonsv output directory.
  802. pub fn nanomonsv_output_dir(&self, id: &str, time: &str) -> String {
  803. self.nanomonsv_output_dir
  804. .replace("{result_dir}", &self.result_dir)
  805. .replace("{id}", id)
  806. .replace("{time}", time)
  807. }
  808. /// Paired nanomonsv *PASSED* VCF.
  809. pub fn nanomonsv_passed_vcf(&self, id: &str) -> String {
  810. self.nanomonsv_passed_vcf
  811. .replace("{output_dir}", &self.nanomonsv_output_dir(id, "diag"))
  812. .replace("{id}", id)
  813. }
  814. /// Solo nanomonsv output directory.
  815. pub fn nanomonsv_solo_output_dir(&self, id: &str, time: &str) -> String {
  816. self.nanomonsv_solo_output_dir
  817. .replace("{result_dir}", &self.result_dir)
  818. .replace("{id}", id)
  819. .replace("{time}", time)
  820. }
  821. /// Solo nanomonsv *PASSED* VCF.
  822. pub fn nanomonsv_solo_passed_vcf(&self, id: &str, time: &str) -> String {
  823. self.nanomonsv_solo_passed_vcf
  824. .replace("{output_dir}", &self.nanomonsv_solo_output_dir(id, time))
  825. .replace("{id}", id)
  826. .replace("{time}", time)
  827. }
  828. /// Savana output directory (`{result_dir}`, `{id}`).
  829. pub fn savana_output_dir(&self, id: &str) -> String {
  830. self.savana_output_dir
  831. .replace("{result_dir}", &self.result_dir)
  832. .replace("{id}", id)
  833. }
  834. /// Savana main somatic VCF (classified).
  835. pub fn savana_output_vcf(&self, id: &str) -> String {
  836. let output_dir = self.savana_output_dir(id);
  837. format!(
  838. "{output_dir}/{id}_{}_{}_{}.classified.somatic.vcf",
  839. self.tumoral_name, self.reference_name, self.haplotagged_bam_tag_name
  840. )
  841. }
  842. /// Savana *PASSED* VCF.
  843. pub fn savana_passed_vcf(&self, id: &str) -> String {
  844. self.savana_passed_vcf
  845. .replace("{output_dir}", &self.savana_output_dir(id))
  846. .replace("{id}", id)
  847. }
  848. /// Savana read counts file.
  849. pub fn savana_read_counts(&self, id: &str) -> String {
  850. self.savana_read_counts
  851. .replace("{output_dir}", &self.savana_output_dir(id))
  852. .replace("{id}", id)
  853. .replace("{reference_name}", &self.reference_name)
  854. .replace("{haplotagged_bam_tag_name}", &self.haplotagged_bam_tag_name)
  855. }
  856. /// Savana copy-number file.
  857. pub fn savana_copy_number(&self, id: &str) -> String {
  858. self.savana_copy_number
  859. .replace("{output_dir}", &self.savana_output_dir(id))
  860. .replace("{id}", id)
  861. .replace("{reference_name}", &self.reference_name)
  862. .replace("{haplotagged_bam_tag_name}", &self.haplotagged_bam_tag_name)
  863. }
  864. /// CoRAl
  865. pub fn coral_output_dir(&self, id: &str) -> String {
  866. format!(
  867. "{}/{}/{}/coral/output",
  868. self.result_dir, id, self.tumoral_name
  869. )
  870. }
  871. pub fn coral_work_dir(&self, id: &str) -> String {
  872. format!(
  873. "{}/{}/{}/coral/work",
  874. self.result_dir, id, self.tumoral_name
  875. )
  876. }
  877. pub fn savana_fitted_purity_ploidy(&self, id: &str) -> String {
  878. // adjust the glob pattern to match your actual SAVANA output naming
  879. format!(
  880. "{}/{}/{}/savana/{}_*_fitted_purity_ploidy.tsv",
  881. self.result_dir, id, self.tumoral_name, id
  882. )
  883. }
  884. pub fn savana_segmented_absolute_cn(&self, id: &str) -> String {
  885. format!(
  886. "{}/{}/{}/savana/{}_*_segmented_absolute_copy_number.tsv",
  887. self.result_dir, id, self.tumoral_name, id
  888. )
  889. }
  890. /// Severus paired output directory.
  891. pub fn severus_output_dir(&self, id: &str) -> String {
  892. self.severus_output_dir
  893. .replace("{result_dir}", &self.result_dir)
  894. .replace("{id}", id)
  895. }
  896. /// Severus somatic SV VCF (paired).
  897. pub fn severus_output_vcf(&self, id: &str) -> String {
  898. let output_dir = self.severus_output_dir(id);
  899. format!("{output_dir}/somatic_SVs/severus_somatic.vcf")
  900. }
  901. /// Severus *PASSED* VCF (paired).
  902. pub fn severus_passed_vcf(&self, id: &str) -> String {
  903. format!(
  904. "{}/{}_diag_severus_PASSED.vcf.gz",
  905. &self.severus_output_dir(id),
  906. id
  907. )
  908. }
  909. /// Severus solo output directory.
  910. pub fn severus_solo_output_dir(&self, id: &str, time: &str) -> String {
  911. self.severus_solo_output_dir
  912. .replace("{result_dir}", &self.result_dir)
  913. .replace("{id}", id)
  914. .replace("{time}", time)
  915. }
  916. /// Severus solo SV VCF.
  917. pub fn severus_solo_output_vcf(&self, id: &str, time: &str) -> String {
  918. let output_dir = self.severus_solo_output_dir(id, time);
  919. format!("{output_dir}/all_SVs/severus_all.vcf")
  920. }
  921. /// Severus solo *PASSED* VCF.
  922. pub fn severus_solo_passed_vcf(&self, id: &str, time: &str) -> String {
  923. format!(
  924. "{}/{}_{}_severus-solo_PASSED.vcf.gz",
  925. &self.severus_solo_output_dir(id, time),
  926. id,
  927. time
  928. )
  929. }
  930. /// Straglr paired output directory.
  931. pub fn straglr_output_dir(&self, id: &str) -> String {
  932. self.straglr_output_dir
  933. .replace("{result_dir}", &self.result_dir)
  934. .replace("{id}", id)
  935. }
  936. /// Straglr normal sample TSV output.
  937. pub fn straglr_normal_tsv(&self, id: &str) -> String {
  938. format!(
  939. "{}/{}_{}_straglr.tsv",
  940. self.straglr_solo_output_dir(id, &self.normal_name),
  941. id,
  942. self.normal_name
  943. )
  944. }
  945. /// Straglr tumor sample TSV output.
  946. pub fn straglr_tumor_tsv(&self, id: &str) -> String {
  947. format!(
  948. "{}/{}_{}_straglr.tsv",
  949. self.straglr_output_dir(id),
  950. id,
  951. self.tumoral_name
  952. )
  953. }
  954. /// Straglr tumor sample TSV output.
  955. pub fn straglr_tumor_normal_diff_tsv(&self, id: &str) -> String {
  956. format!(
  957. "{}/{}_{}_straglr_diff.tsv",
  958. self.straglr_output_dir(id),
  959. id,
  960. self.tumoral_name
  961. )
  962. }
  963. /// Straglr solo output directory.
  964. pub fn straglr_solo_output_dir(&self, id: &str, time: &str) -> String {
  965. self.straglr_solo_output_dir
  966. .replace("{result_dir}", &self.result_dir)
  967. .replace("{id}", id)
  968. .replace("{time}", time)
  969. }
  970. /// Straglr solo TSV output.
  971. pub fn straglr_solo_tsv(&self, id: &str, time: &str) -> String {
  972. format!(
  973. "{}/{}_{}_straglr.tsv",
  974. self.straglr_solo_output_dir(id, time),
  975. id,
  976. time
  977. )
  978. }
  979. /// Alias for the constitutional germline VCF.
  980. pub fn constit_vcf(&self, id: &str) -> String {
  981. self.clairs_germline_passed_vcf(id)
  982. }
  983. /// Somatic-scan output directory for a solo run (counts subdir).
  984. pub fn somatic_scan_solo_output_dir(&self, id: &str, time: &str) -> String {
  985. format!("{}/counts", self.solo_dir(id, time))
  986. }
  987. /// Somatic-scan output dir for the normal sample.
  988. pub fn somatic_scan_normal_output_dir(&self, id: &str) -> String {
  989. self.somatic_scan_solo_output_dir(id, &self.normal_name)
  990. }
  991. /// Somatic-scan output dir for the tumor sample.
  992. pub fn somatic_scan_tumoral_output_dir(&self, id: &str) -> String {
  993. self.somatic_scan_solo_output_dir(id, &self.tumoral_name)
  994. }
  995. /// Somatic-scan count file for a given contig in a solo run.
  996. pub fn somatic_scan_solo_count_file(&self, id: &str, time: &str, contig: &str) -> String {
  997. format!(
  998. "{}/{}_count.tsv.gz",
  999. self.somatic_scan_solo_output_dir(id, time),
  1000. contig
  1001. )
  1002. }
  1003. /// Somatic-scan count file (normal) for a given contig.
  1004. pub fn somatic_scan_normal_count_file(&self, id: &str, contig: &str) -> String {
  1005. self.somatic_scan_solo_count_file(id, &self.normal_name, contig)
  1006. }
  1007. /// Somatic-scan count file (tumor) for a given contig.
  1008. pub fn somatic_scan_tumoral_count_file(&self, id: &str, contig: &str) -> String {
  1009. self.somatic_scan_solo_count_file(id, &self.tumoral_name, contig)
  1010. }
  1011. /// Modkit summary file (`{result_dir}`, `{id}`, `{time}`).
  1012. pub fn modkit_summary_file(&self, id: &str, time: &str) -> String {
  1013. self.modkit_summary_file
  1014. .replace("{result_dir}", &self.result_dir)
  1015. .replace("{id}", id)
  1016. .replace("{time}", time)
  1017. }
  1018. /// Longphase modcall VCF (`{result_dir}`, `{id}`, `{time}`).
  1019. pub fn longphase_modcall_vcf(&self, id: &str, time: &str) -> String {
  1020. self.longphase_modcall_vcf
  1021. .replace("{result_dir}", &self.result_dir)
  1022. .replace("{id}", id)
  1023. .replace("{time}", time)
  1024. }
  1025. /// longcallD output directory (`{result_dir}`, `{id}`, `{time}`).
  1026. pub fn longcalld_output_dir(&self, id: &str, time: &str) -> String {
  1027. self.longcalld_output_dir
  1028. .replace("{result_dir}", &self.result_dir)
  1029. .replace("{id}", id)
  1030. .replace("{time}", time)
  1031. }
  1032. /// longcallD solo *PASSED* VCF for `<id>, <time>`.
  1033. pub fn longcalld_solo_passed_vcf(&self, id: &str, time: &str) -> String {
  1034. format!(
  1035. "{}/{}_{}_longcallD_PASSED.vcf.gz",
  1036. self.longcalld_output_dir(id, time),
  1037. id,
  1038. time
  1039. )
  1040. }
  1041. pub fn longcalld_solo_bam(&self, id: &str, time: &str) -> String {
  1042. format!(
  1043. "{}/{}_{}_{}_{}_realn.bam",
  1044. self.solo_dir(id, time),
  1045. id,
  1046. time,
  1047. self.reference_name,
  1048. self.haplotagged_bam_tag_name
  1049. )
  1050. }
  1051. }
  1052. impl Default for Config {
  1053. fn default() -> Self {
  1054. let path = Self::config_path();
  1055. Self::from_path(path)
  1056. }
  1057. }