Skip to content
Snippets Groups Projects
SNAKEFILE 109 KiB
Newer Older
"""
Author: C. Laczny
Affiliation: ESB group LCSB UniLU
Aim:
Date: [25 June 2019]
Run: snakemake -s Snakefile
Modified on: 2020-04-23
Modified for: New_Basecalling, Mapping to Hybrid assembly, metaT mapping, Binning, CheckM and GTDBTK
TODO:
s. TODO.md
"""

#shell.executable("/bin/bash")
#shell.prefix("source ~/.bashrc; ")
import os
from tempfile import TemporaryDirectory

configfile: "CONFIG.yaml"
DATA_DIR = config["data_dir"]
RESULTS_DIR = config["results_dir"]
DB_DIR=config["db_dir"]
RUNS=[config["runs"]["first"],
    config["runs"]["second"],
    config["runs"]["third"]]
##RUNS=config["runs"]["third"]
BARCODES=config["barcodes"]
#SAMPLES=["NEB2_MG_S17"]
#SAMPLES_ALL=config["samples"]
REFERENCES=["igc", "hg38"]
IGC_URI=config["igc"]["uri"]
HG38_URI=config["hg38"]["uri"]
ASSEMBLERS=config["assemblers"]
#MAPPERS=["bwa_mem", "minimap2"]


#configfile:"binning_config.yaml"
DATA_DIR=config["data_dir"]
RESULTS_DIR=config["results_dir"]
SAMPLES=config["samples"]
# DATABASE=config["database"]
BINNING_SAMPLES=config["binning_samples"]
HYBRID_ASSEMBLER=config["hybrid_assembler"]

############
rule all:
    #input: expand("{data_dir}/multifast5/{run}", data_dir=DATA_DIR, run=RUNS)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled/guppy/cpu/{run}/basecalling.done"), run=RUNS)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled/{run}/basecalling.done"), run=RUNS)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/NO_MOD_basecalling.done"), run=RUNS)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled/{run}/demux.done"), run=RUNS)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/demux_NO_MOD.done"), run=RUNS)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled/{run}/{barcode}/{barcode}.fastq.gz"), run=RUNS, barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/{barcode}/{barcode}.fastq.gz"), run=RUNS, barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fastq.gz"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "basecalled_NO_MOD/merged/{barcode}.fastq.gz"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "qc/lr/merged/{barcode}/{barcode}NanoStats.txt"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "qc/lr/merged/{barcode}/{barcode}NanoStats_NO_MOD.txt"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "qc/lr/{run}/{barcode}/{barcode}NanoStats.txt"), run=RUNS, barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "qc/lr/{run}/{barcode}/{barcode}NanoStats_NO_MOD.txt"), run=RUNS, barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "mapping/guppy/gpu/{barcode}/{barcode}-long_reads_on_short_reads.sam"), barcode=BARCODES)		# checked with CCL. not required (legacy)
    #input: expand(os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}-x-igc.bam"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}-x-hg38.bam"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "preprocessing/sr/{sr_sample}_R1_001.fastp.fq.gz"), sr_sample="NEB2_MG_S17")
    # not required (legacy code) input: expand(os.path.join(RESULTS_DIR, "mapping/sr/{sample}-x-igc.bam"), sample="NEB2_MG_S17")
    # not required (legacy code) input: expand(os.path.join(RESULTS_DIR, "mapping/sr/{sample}-x-hg38.bam"), sample="NEB2_MG_S17")
    #input: expand(os.path.join(RESULTS_DIR, "mapping/sr/{mapper}/{sample}-x-{reference}.bam"), sample="NEB2_MG_S17", reference=REFERENCES, mapper=MAPPERS)
    #input: expand(os.path.join(RESULTS_DIR, "mapping/sr/{mapper}/{sr_sample}_reads-x-{barcode}-{assembler}_contigs.bam"), sr_sample="NEB2_MG_S17", barcode=BARCODES, assembler=ASSEMBLERS, mapper=MAPPERS)
    #input: expand(os.path.join(RESULTS_DIR, "genomecov/lr/merged/{barcode}/{barcode}-x-igc.cov.txt"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "genomecov/sr/{mapper}/{sample}-x-igc.avg_cov.txt"), sample="NEB2_MG_S17", mapper=MAPPERS)
    #input: expand(os.path.join(RESULTS_DIR, "genomecov/lr/merged/{barcode}/{barcode}-x-igc.avg_cov.txt"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "mapping/lr/merged/{sample}-x-{barcode}.bam"), sample=SAMPLES, barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "assembly/flye/lr/merged/{barcode}/assembly.fna"), barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_contigs.bam"), barcode=BARCODES, assembler=ASSEMBLERS)
    #input: expand(os.path.join(RESULTS_DIR, "genomecov/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_contigs.avg_cov.txt"), barcode=BARCODES, assembler=ASSEMBLERS)
    #input: expand(os.path.join(RESULTS_DIR, "mapping/sr/{mapper}/{sample}_reads-x-{barcode}-{assembler}_contigs.bam"), sample=SAMPLES, barcode=BARCODES, assembler=ASSEMBLERS, mapper=MAPPERS)
    #input: expand(os.path.join(RESULTS_DIR, "genomecov/sr/{mapper}/{sample}_reads-x-{barcode}-{assembler}_contigs.avg_cov.txt"), sample=SAMPLES, barcode=BARCODES, assembler=ASSEMBLERS, mapper=MAPPERS)
    #input: "assemble_and_coverage.done"
    #input: expand(os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/medaka/round_{round}/lr/merged/{barcode}/assembly_polished.fna"), assembler=ASSEMBLERS, barcode=BARCODES, round="01")
    #input: "basecall_merge_qc.done"
    #input: "basecall_merge_qc_NO_MOD.done"
    #input: "coverage_of_references.done"
    #input: expand(os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fastq.gz.index.readdb"), barcode=BARCODES)
    #input: "annotate.done"
    #input: expand(os.path.join(RESULTS_DIR, "qc/lr/{run}/{barcode}/{barcode}NanoStats.txt"), run=RUNS, barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "qc/sr/fastqc/{sr_sample}/{sr_sample}_{suffix}.fastqc.zip"), sr_sample="NEB2_MG_S17",suffix=["R1_001.fastp", "R2_001.fastp"])
    #input: expand(os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/racon/round_{round}/lr/merged/{barcode}/assembly_polished.fna"), barcode=BARCODES, assembler=ASSEMBLERS, round="01")
    #input: expand(os.path.join(RESULTS_DIR, "assembly/metaspades_hybrid/lr_{barcode}-sr_{sr_sample}/contigs.fna"), barcode=BARCODES, sr_sample="NEB2_MG_S17")
    # specifc HYBRID_ASSEBMLERS instead of ASSEMBLERS; not sure if this will solve the issue, though. #input: expand(os.path.join(RESULTS_DIR, "mapping/sr/bwa_mem/{sr_sample}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs.bam"), barcode=BARCODES, assembler=ASSEMBLERS, sr_sample="NEB2_MG_S17")
    # RUN AFTER line #80 #input: expand(os.path.join(RESULTS_DIR, "mapping/lr/bwa_mem/{barcode}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs.bam"), barcode=BARCODES, assembler=ASSEMBLERS, sr_sample="NEB2_MG_S17")
    #input: expand(os.path.join(RESULTS_DIR, "mapping/polished/{polisher}/round_{round}/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_polished_contigs.bam"),  barcode=BARCODES, assembler=ASSEMBLERS, round="01", polisher="medaka")
    #input: expand(os.path.join(RESULTS_DIR, "assembly/megahit/{sr_sample}/final.contigs.fna"), sr_sample="NEB2_MG_S17")
    ### RUN LATER #input: expand(os.path.join(RESULTS_DIR, "mapping/lr/bwa_mem/{barcode}_reads-x-{sr_sample}-{assembler}_contigs.bam"), barcode=BARCODES, assembler=ASSEMBLERS, sr_sample="NEB2_MG_S17")
    #input: expand(os.path.join(RESULTS_DIR, "annotation/nonpareil/{sr_sample}_R{orientation}_{suffix}.fastp.npo"), sr_sample="NEB2_MG_S17", orientation=["1", "2"], suffix="001")
    #input: expand(os.path.join(RESULTS_DIR, "assembly/flye/polished/nanopolish/round_{round}/lr/merged/{barcode}/windows"), round="01", barcode=BARCODES)
    input: expand(os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/nanopolish/round_{round}/lr/merged/{barcode}/assembly_polished.fna"), assembler=ASSEMBLERS, round="01", barcode=BARCODES)
    ### RUN LATER #input: expand(os.path.join(RESULTS_DIR, "annotation/methylation/{assembler}/nanopolish/round_{round}/lr/merged/{barcode}/methylation_frequencies.tsv"), assembler=ASSEMBLERS, round="01", barcode=BARCODES)
    #input: expand(os.path.join(RESULTS_DIR, "annotation/diamond/lr/merged/{barcode}.diamond.daa"), barcode=BARCODES)
    #input: expand(f"{RESULTS_DIR}/annotation/mmseq2/{{assembler1}}__{{assembler2}}_rbh"), zip, assembler1=["flye", "flye", "megahit"], assembler2=["megahit", "megahit_metaspades_hybrid", "megahit_metaspades_hybrid"])


######
# WRAPPER RULES
######
# Added the `shell:` so as to avoid it from being autodetected as `localrule`. This is needed so that an email can be sent upon event changes for this rule.
rule BASECALL_MERGE_QC:
    input:
        expand(os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fastq.gz"), barcode=BARCODES),
        expand(os.path.join(RESULTS_DIR, "qc/lr/merged/{barcode}/{barcode}NanoStats.txt"), barcode=BARCODES),
        expand(os.path.join(RESULTS_DIR, "qc/lr/{run}/{barcode}/{barcode}NanoStats.txt"), run=RUNS, barcode=BARCODES),
        expand(os.path.join(RESULTS_DIR, "preprocessing/sr/{sample}.fastp.{report_type}"), sample=SAMPLES, report_type=["html", "json"]),
        expand(os.path.join(RESULTS_DIR, "qc/sr/fastqc/{sample}/{sample}_R{orientation}_001.fastp.fastqc.html"), sample=SAMPLES, orientation=["1", "2"])
    output: "basecall_merge_qc.done"
    shell:
        """
        touch {output}
        """

rule BASECALL_MERGE_QC_NO_MOD:
    input:
        expand(os.path.join(RESULTS_DIR, "basecalled_NO_MOD/merged/{barcode}.fastq.gz"), barcode=BARCODES),
        expand(os.path.join(RESULTS_DIR, "qc/lr/merged/{barcode}/{barcode}NanoStats_NO_MOD.txt"), barcode=BARCODES),
        expand(os.path.join(RESULTS_DIR, "qc/lr/{run}/{barcode}/{barcode}NanoStats_NO_MOD.txt"), run=RUNS, barcode=BARCODES)
    output: "basecall_merge_qc_NO_MOD.done"
    shell:
        """
        touch {output}
        """

rule COVERAGE_OF_REFERENCES:
    input: 
        expand(os.path.join(RESULTS_DIR, "genomecov/sr/minimap2/{sample}-x-{reference}.avg_cov.txt"), sample=SAMPLES, reference=REFERENCES),
        expand(os.path.join(RESULTS_DIR, "genomecov/sr/bwa_mem/{sample}-x-{reference}.avg_cov.txt"), sample=SAMPLES, reference=REFERENCES),
        expand(os.path.join(RESULTS_DIR, "genomecov/lr/merged/{barcode}/{barcode}-x-{reference}.avg_cov.txt"), barcode=BARCODES, reference=REFERENCES)
    output: "coverage_of_references.done"
    shell:
        """
        touch {output}
        """

rule TEST:
        input:
            # Commented out as it crashes due to a Key error
            #expand(os.path.join(RESULTS_DIR, "assembly/rebaler/lr/merged/{barcode}/lr_{barcode}-sr_contigs_{sample}.fna"), barcode=BARCODES, sample=SAMPLES)
            expand(os.path.join(RESULTS_DIR, "annotation/diamond/lr/merged/{barcode}.diamond.daa"), barcode=BARCODES),
            expand(os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sample}/contigs.fna"), barcode=BARCODES, sample=SAMPLES, assembler="metaspades_hybrid")

rule TEST_PRODIGAL:
        input:
            expand(os.path.join(RESULTS_DIR, "annotation/proteins/{assembler}/lr/merged/{barcode}/assembly.faa"), assembler="flye", barcode=BARCODES),
            expand(os.path.join(RESULTS_DIR, "annotation/proteins/{assembler}/polished/{polisher}/round_{round}/lr/merged/{barcode}/assembly_polished.faa"), assembler="flye", polisher=["medaka", "racon"], round="01", barcode=BARCODES),
            expand(os.path.join(RESULTS_DIR, "annotation/proteins/{assembler}/{sample}/final.contigs.faa"), assembler="megahit", sample=SAMPLES),
            expand(os.path.join(RESULTS_DIR, "annotation/proteins/{assembler}/lr_{barcode}-sr_{sample}/contigs.faa"), assembler="metaspades_hybrid", barcode=BARCODES, sample=SAMPLES)
        output: "prodigal_gene_call.done"
        shell:
            """
            touch {output}
            """

rule TEST_DIAMOND:
        input:
            expand(os.path.join(RESULTS_DIR, "annotation/diamond/{assembler}/lr/merged/{barcode}/assembly.tsv"), assembler="flye", barcode=BARCODES),
            expand(os.path.join(RESULTS_DIR, "annotation/diamond/{assembler}/polished/{polisher}/round_{round}/lr/merged/{barcode}/assembly_polished.tsv"), assembler="flye", polisher=["medaka", "racon"], round="01", barcode=BARCODES),
            expand(os.path.join(RESULTS_DIR, "annotation/diamond/{assembler}/{sample}/final.contigs.tsv"), assembler="megahit", sample=SAMPLES),
            expand(os.path.join(RESULTS_DIR, "annotation/diamond/{assembler}/lr_{barcode}-sr_{sample}/contigs.tsv"), assembler="metaspades_hybrid", barcode=BARCODES, sample=SAMPLES)
        output: "diamond_proteins.done"
        shell:
            """
            touch {output}
            """


rule ASSEMBLE_AND_COVERAGE:
    input:
        # long reads on long read contigs
        expand(os.path.join(RESULTS_DIR, "genomecov/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_contigs.avg_cov.txt"), barcode=BARCODES, assembler=ASSEMBLERS),
        # short reads on long read contigs
        expand(os.path.join(RESULTS_DIR, "genomecov/sr/minimap2/{sample}_reads-x-{barcode}-{assembler}_contigs.avg_cov.txt"), sample=SAMPLES, barcode=BARCODES, assembler=ASSEMBLERS),
        # short reads on long read contigs
        expand(os.path.join(RESULTS_DIR, "genomecov/sr/bwa_mem/{sample}_reads-x-{barcode}-{assembler}_contigs.avg_cov.txt"), sample=SAMPLES, barcode=BARCODES, assembler=ASSEMBLERS),
        #expand(os.path.join(RESULTS_DIR, "assembly/operams/lr_{barcode}-sr_{sample}/contigs.fna"), sample=SAMPLES, barcode=BARCODES),
        #expand(os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_contigs.bam"), barcode=BARCODES, assembler="flye"),
        # short reads on hybrid contigs
        #expand(os.path.join(RESULTS_DIR, "genomecov/sr/bwa_mem/{sample}_reads-x-lr_{barcode}_sr_{sample}-{assembler}_contigs.avg_cov.txt"), sample=SAMPLES, barcode=BARCODES, assembler="operams"),
        # long reads on hybrid contigs
        #expand(os.path.join(RESULTS_DIR, "genomecov/lr/bwa_mem/{barcode}_reads-x-lr_{barcode}_sr_{sample}-{assembler}_contigs.avg_cov.txt"), barcode=BARCODES, sample=SAMPLES, assembler="operams"),
        #expand(os.path.join(RESULTS_DIR, "assembly/flye/lr/merged/{barcode}/assembly.fna"), barcode=BARCODES)
        # short reads on short read contigs
        expand(os.path.join(RESULTS_DIR, "genomecov/sr/bwa_mem/{sample}_reads-x-{sample}-{assembler}_contigs.avg_cov.txt"), sample=SAMPLES, assembler="megahit"),
        # long reads on short read contigs
        expand(os.path.join(RESULTS_DIR, "genomecov/lr/bwa_mem/{barcode}_reads-x-{sample}-{assembler}_contigs.avg_cov.txt"), barcode=BARCODES, sample=SAMPLES, assembler="megahit")
    output: "assemble_and_coverage.done"
    shell:
        """
        touch {output}
        """

rule ANNOTATE:
    input:
        # short reads coverage and diversity estimate
        expand(os.path.join(RESULTS_DIR, "annotation/nonpareil/{sample}_R{orientation}_001.fastp.npa"), sample=SAMPLES, orientation=["1", "2"]),
        # compute methylation frequencies
        expand(os.path.join(RESULTS_DIR, "annotation/methylation/{assembler}/nanopolish/round_{round}/lr/merged/{barcode}/methylation_frequencies.tsv"), assembler="flye", barcode=BARCODES, round="01")
    output: "annotate.done"
    shell:
        """
        touch {output}
        """
        
rule POLISH_AND_COVERAGE:
    input:
        # short read-polished contigs from OPERA-MS
        #expand(os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sample}/contigs.fna"), sample=SAMPLES, barcode=BARCODES, assembler="operams"),
        #long read polished contigs
        #expand(os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/{polisher}/round_{round}/lr/merged/{barcode}/assembly_polished.fna"), assembler="flye", polisher="medaka", round="01", barcode=BARCODES),
        # map long reads to long read polished contigs
        expand(os.path.join(RESULTS_DIR, "genomecov/polished/{polisher}/round_{round}/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_polished_contigs.avg_cov.txt"), assembler="flye", polisher="medaka", round="01", barcode=BARCODES),
        # create nanonoplish index
        #expand(os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fastq.gz.index.readdb"), barcode=BARCODES)
        # polish flye contigs with nanopolish
        #expand(os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/nanopolish/round_{round}/lr/merged/{barcode}/assembly_polished.fna"), assembler="flye", round="01", barcode=BARCODES),
        # polish using racon
        expand(os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/racon/round_{round}/lr/merged/{barcode}/assembly_polished.fna"), assembler="flye", round="01", barcode=BARCODES)


rule DB_MMSEQ2:
    input:
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/{assembler}_db"), assembler=["flye", "megahit", "metaspades_hybrid"])

rule COMPARE_MMSEQ2:
    input:
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/flye_megahit_rbh")),
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/flye_metaspades_hybrid_rbh")),
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/megahit_metaspades_hybrid_rbh"))

rule CONVERT_MMSEQ2:
    input:
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/flye_megahit.m8")),
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/flye_metaspades_hybrid.m8")),
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/megahit_metaspades_hybrid.m8"))

rule PREPARE_FILES:
    input:
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/plot_files_ready.done"))

rule PLOT_MMSEQ2:
    input:
#        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/plot_files_ready.done")),
        expand(os.path.join(RESULTS_DIR, "annotation/mmseq2/upset_plots.done")) 

rule METAT:
    input:
        expand(os.path.join(RESULTS_DIR, "preprocessing/metaT/{metaT_sample}.fastp.{report_type}"), metaT_sample="GDB_2018_metaT", report_type=["html", "json"]),
#	expand(os.path.join(RESULTS_DIR, "mapping/metaT/lr/{metaT_sample}-x-{barcode}.bam"), metaT_sample="GDB_2018_metaT", barcode=BARCODES),
        expand(os.path.join(RESULTS_DIR, "mapping/metaT/sr/{metaT_sample}_reads-x-{sr_sample}-{assembler}_contigs.bam"), metaT_sample="GDB_2018_metaT", sr_sample="NEB2_MG_S17", assembler="megahit"),
        expand(os.path.join(RESULTS_DIR, "mapping/metaT/sr/{metaT_sample}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs.bam"), metaT_sample="GDB_2018_metaT", sr_sample="NEB2_MG_S17", barcode=BARCODES, assembler="metaspades_hybrid"),
        expand(os.path.join(RESULTS_DIR, "mapping/metaT/lr/{metaT_sample}_reads-x-{barcode}-{assembler}_contigs.bam"), metaT_sample="GDB_2018_metaT", barcode=BARCODES, assembler=ASSEMBLERS),
        expand(os.path.join(RESULTS_DIR, "genomecov/metaT/sr/{metaT_sample}_reads-x-{sr_sample}-{assembler}_contigs.avg_cov.txt"), metaT_sample="GDB_2018_metaT", sr_sample="NEB2_MG_S17", assembler="megahit"),
        expand(os.path.join(RESULTS_DIR, "genomecov/metaT/sr/{metaT_sample}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs.avg_cov.txt"), metaT_sample="GDB_2018_metaT", sr_sample="NEB2_MG_S17", barcode=BARCODES, assembler="metaspades_hybrid"),
        expand(os.path.join(RESULTS_DIR, "genomecov/metaT/lr/{metaT_sample}_reads-x-{barcode}-{assembler}_contigs.avg_cov.txt"), metaT_sample="GDB_2018_metaT", barcode=BARCODES, assembler=ASSEMBLERS)


rule MAPPING:
    input:
        expand(os.path.join(RESULTS_DIR, "mapping/{hybrid_assembler}/metaspades.bwt"), hybrid_assembler=HYBRID_ASSEMBLER),
        expand(os.path.join(RESULTS_DIR, "mapping/{mapper}_{reads}_{hybrid_assembler}/{mapper}_{reads}_{hybrid_assembler}.bam"), mapper=["bwa", "mmi"], reads=["sr", "lr"], hybrid_assembler=HYBRID_ASSEMBLER),
        expand(os.path.join(RESULTS_DIR, "mapping/{hybrid_assembler}/{hybrid_assembler}.mmi"), hybrid_assembler=HYBRID_ASSEMBLER),
        expand(os.path.join(RESULTS_DIR, "mapping/{mapper}_merged_{hybrid_assembler}/{mapper}_merged_{hybrid_assembler}.bam"), mapper=["bwa", "mmi"], hybrid_assembler=HYBRID_ASSEMBLER)


rule BINNING:
    input:
#        expand(os.path.join(DATA_DIR, "{sample}/dastool_output/{sample}"), sample=BINNING_SAMPLES),
#        expand(os.path.join(DATA_DIR, "checkm_output/{sample}/lineage.ms"), sample=BINNING_SAMPLES)
#        expand(os.path.join(DATA_DIR, "gtdbtk_output/{sample}/gtdbtk.bac120.summary.tsv"), sample=BINNING_SAMPLES)
        expand(os.path.join(RESULTS_DIR, "assembly/{sample}.fa"), sample=BINNING_SAMPLES),
        expand(os.path.join(RESULTS_DIR, "Binning/{sample}/dastool_output/{sample}_proteins.faa"), sample=BINNING_SAMPLES),
        expand(os.path.join(RESULTS_DIR, "Binning/checkm_output/{sample}_output.txt"), sample=BINNING_SAMPLES),
        expand(os.path.join(RESULTS_DIR, "Binning/gtdbtk_output/{sample}/gtdbtk.bac120.summary.tsv"), sample=BINNING_SAMPLES)



282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
######
# RULES
######       
# rule unpack:
#     input: os.path.join(DATA_DIR, "2018-11-08-minion_latestdata.7z")
#     output: os.path.join(DATA_DIR, "raw/raw_unpacked.done")
#     threads: config["p7zip"]["threads"]
#     shell:
#         """
#         date
#         {config[p7zip][bin]} x -o$(dirname {output}) {input} -mmt{threads} &> {output}
#         date
#         """

# Take the per-read FAST5 files and create multi-FAST5 files including a batch of reads (typically not all reads, though).
rule create_multifast5s:
    input: os.path.join(DATA_DIR, "raw/{run}")
    output: protected(directory(os.path.join(DATA_DIR, "multifast5/{run}")))
    threads: config["ont_fast5_api"]["single_to_multi_fast5"]["threads"]
    log: os.path.join(DATA_DIR, "multifast5/{run}/create_multifast5s")
    shell:
        """
        (date &&\
        {config[ont_fast5_api][single_to_multi_fast5][bin]} --input_path {input} --save_path {output} --filename_base multifast5 --batch_size {config[ont_fast5_api][single_to_multi_fast5][batch]} --recursive -t {threads} &&\
        touch {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# FLO-MIN107 SQK-LSK108           dna_r9.5_450bps
#   --verbose_logs                    Enable verbose logs.
#   --qscore_filtering                Enable filtering of reads into PASS/FAIL
#                                     folders based on min qscore.
#   --min_qscore arg                  Minimum acceptable qscore for a read to be
#                                     filtered into the PASS folder
#   --disable_pings                   Disable the transmission of telemetry
#   --num_callers arg                 Number of parallel basecallers to create.
#   --num_barcode_threads arg         Number of worker threads to use for
#                                     barcoding.
#   --barcode_kits arg                Space separated list of barcoding kit(s) or
#                                     expansion kit(s) to detect against. Must be
#                                     in double quotes.
#   --trim_barcodes                   Trim the barcodes from the output sequences
#                                     in the FastQ files.

# Left in for legacy look-up reasons. GPU-based basecalling strongly encouraged.
# rule guppy_cpu_basecall:
#     input: os.path.join(DATA_DIR, "multifast5/{run}")
#     output: os.path.join(RESULTS_DIR, "basecalled/guppy/cpu/{run}/basecalling.done")
#     threads: config["guppy_cpu"]["cpu_threads"]
#     shell:
#         """
#         date
#         {config[guppy_cpu][bin]} --input_path {input} --save_path $(dirname {output}) --config {config[guppy_cpu][config]} --cpu_threads_per_caller {threads} --disable_pings
#         touch {output}
#         date
#         """

    #input: os.path.join(DATA_DIR, "multifast5/{run}")
# Basecalling the multi-FAST5 files.
# Currently requires dummy target, but would be nice to have this be a "real" file target. However, it seems that files are filled incrementally, hence there is no check if the whole process was successful or not if checking only for file presence.
rule guppy_gpu_basecall:
    input: rules.create_multifast5s.output
    output: os.path.join(RESULTS_DIR, "basecalled/{run}/basecalling.done")
    log: os.path.join(RESULTS_DIR, "basecalled/{run}/basecalling")
    threads: config["guppy_gpu"]["cpu_threads"]
    shell:
        """
        (date &&\
        {config[guppy_gpu][bin]} --input_path {input} --save_path $(dirname {output}) --config {config[guppy_gpu][config]} --cpu_threads_per_caller {threads} -x {config[guppy_gpu][gpu_device]} --disable_pings --compress_fastq --records_per_fastq {config[guppy_gpu][records_per_fastq]} --chunk_size {config[guppy_gpu][chunk_size]} --chunks_per_runner {config[guppy_gpu][chunks_per_runner]} --gpu_runners_per_device {config[guppy_gpu][runners_per_device]} --num_callers {config[guppy_gpu][num_callers]} && \
        touch {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

rule guppy_gpu_basecall_NO_MOD:
    input: rules.create_multifast5s.output
    output: os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/NO_MOD_basecalling.done")
    log: os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/NO_MOD_basecalling")
    threads: config["guppy_gpu"]["cpu_threads"]
    shell: 
        """
        (date &&\
        {config[guppy_gpu][bin]} --input_path {input} --save_path $(dirname {output}) --config {config[guppy_gpu][hac_config]} --cpu_threads_per_caller {threads} -x {config[guppy_gpu][gpu_device]} --disable_pings --compress_fastq --records_per_fastq {config[guppy_gpu][records_per_fastq]} --chunk_size {config[guppy_gpu][chunk_size]} --chunks_per_runner {config[guppy_gpu][chunks_per_runner]} --gpu_runners_per_device {config[guppy_gpu][runners_per_device]} --num_callers {config[guppy_gpu][num_callers]} && \
        touch {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Demultiplex.
# Currently requires dummy target, but would be nice to have this be a "real" file target. However, it seems that files are filled incrementally, hence there is no check if the whole process was successful or not if checking only for file presence.
rule guppy_gpu_demux:
    input: rules.guppy_gpu_basecall.output
    output: os.path.join(RESULTS_DIR, "basecalled/{run}/demux.done")
    log: os.path.join(RESULTS_DIR, "basecalled/{run}/demux")
    threads: config["guppy_barcoder"]["threads"]
    shell:
        """
        (date &&\
        {config[guppy_barcoder][bin]} --input_path $(dirname {input}) --save_path $(dirname {output}) -t {threads} --compress_fastq --records_per_fastq {config[guppy_gpu][records_per_fastq]} --trim_barcodes && \
        touch {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """
rule guppy_gpu_demux_NO_MOD:
    input: rules.guppy_gpu_basecall_NO_MOD.output
    output: os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/demux_NO_MOD.done")
    log: os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/demux")
    threads: config["guppy_barcoder"]["threads"]
    shell:
        """
        (date &&\
        {config[guppy_barcoder][bin]} --input_path $(dirname {input}) --save_path $(dirname {output}) -t {threads} --compress_fastq --records_per_fastq {config[guppy_gpu][records_per_fastq]} --trim_barcodes && \
        touch {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Merge multiple basecalled files, i.e., FASTQ files per barcode and run. Each multi-FAST5 file will produce a respective FASTQ file.
# TODO: Simplify output path to `basecalled/{run}/{barcode}.fastq.gz`. This will require to change `$(dirname {output})` to `$(dirname {output})/{wildcards.barcode}`
rule merge_individual_fastq_per_barcode:
    input: rules.guppy_gpu_demux.output
    output: os.path.join(RESULTS_DIR, "basecalled/{run}/{barcode}/{barcode}.fastq.gz")
    shell:
        """
        date
        cat $(find $(dirname {output}) -name "*.fastq.gz" | sort) > {output}
        touch {output}
        date
        """

rule merge_individual_fastq_per_barcode_NO_MOD:
    input: rules.guppy_gpu_demux_NO_MOD.output
    output: os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/{barcode}/{barcode}.fastq.gz")
    shell:
        """
        date
        cat $(find $(dirname {output}) -name "*.fastq.gz" | sort) > {output}
        touch {output}
        date
        """

# Helper function to get the input in order to create a *single* fastq file for all runs with the *same* barcode
# TODO: Adjust according to TODO-merge_individual_fastq_per_barcode
def get_all_fastq_for_barcode(wildcards):
    return expand(os.path.join(RESULTS_DIR, "basecalled/{run}/{barcode}/{barcode}.fastq.gz"), run=RUNS, barcode=wildcards.barcode)

def get_all_fastq_for_barcode_NO_MOD(wildcards):
    return expand(os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/{barcode}/{barcode}.fastq.gz"), run=RUNS, barcode=wildcards.barcode)

# Merge basecalled files (FASTQ) per barcode, i.e., combine reads from multiple runs according to their barcode.
rule get_single_fastq_per_barcode:
    input: get_all_fastq_for_barcode 
    output: os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fastq.gz")
    shell:
        """
        date
        cat {input} > {output}
        date
        """
rule get_single_fastq_per_barcode_NO_MOD:
    input: get_all_fastq_for_barcode_NO_MOD
    output: os.path.join(RESULTS_DIR, "basecalled_NO_MOD/merged/{barcode}.fastq.gz")
    shell:
        """
        date
        cat {input} > {output}
        date
        """

# Get basic statistics of the ONT data; over all runs
# TODO: Simplify top of path: replace `lr` by `nanostat`
# TODO: Write more generic: have patterned `input: os.path.join(RESULTS_DIR, "basecalled/{prefix}/{barcode}.fastq.gz")` and patterned `output: os.path.join(RESULTS_DIR, "qc/nanostat/{prefix}/{barcode}/{barcode}NanoStats.txt")
# 
rule nanostat:
    input: rules.get_single_fastq_per_barcode.output
    output: os.path.join(RESULTS_DIR, "qc/lr/merged/{barcode}/{barcode}NanoStats.txt")
    log: os.path.join(RESULTS_DIR, "qc/lr/merged/{barcode}/{barcode}NanoStats")
    conda: "envs/nanostat.yaml"
    shell:
        """
        (date &&\
        NanoStat --fastq {input} --outdir $(dirname {output}) --prefix {wildcards.barcode} -n $(basename -s "" {output}) &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

rule nanostat_NO_MOD:
    input: rules.get_single_fastq_per_barcode_NO_MOD.output
    output: os.path.join(RESULTS_DIR, "qc/lr/merged/{barcode}/{barcode}NanoStats_NO_MOD.txt")
    log: os.path.join(RESULTS_DIR, "qc/lr/merged/{barcode}/{barcode}NanoStats_NO_MOD")
    conda: "envs/nanostat.yaml"
    shell:
        """
        (date &&\
        NanoStat --fastq {input} --outdir $(dirname {output}) --prefix {wildcards.barcode} -n $(basename -s "" {output}) &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# TODO: Deprecated if TODO-nanostat is completed
# Get basic statistics of the ONT data; per run
rule nanostat_per_run:
    input: os.path.join(RESULTS_DIR, "basecalled/{run}/{barcode}/{barcode}.fastq.gz")
    output: os.path.join(RESULTS_DIR, "qc/lr/{run}/{barcode}/{barcode}NanoStats.txt")
    conda: "envs/nanostat.yaml"
    shell:
        """
        date
        NanoStat --fastq {input} --outdir $(dirname {output}) --prefix {wildcards.barcode} -n $(basename -s "" {output})
        date
        """

rule nanostat_per_run_NO_MOD:
    input: os.path.join(RESULTS_DIR, "basecalled_NO_MOD/{run}/{barcode}/{barcode}.fastq.gz")
    output: os.path.join(RESULTS_DIR, "qc/lr/{run}/{barcode}/{barcode}NanoStats_NO_MOD.txt")
    conda: "envs/nanostat.yaml"
    shell:
        """
        date
        NanoStat --fastq {input} --outdir $(dirname {output}) --prefix {wildcards.barcode} -n $(basename -s "" {output})
        date
        """

# Download the IGC (http://www.nature.com/nbt/journal/vaop/ncurrent/full/nbt.2942.html)
# Downloading using wget-command instead of FTP-remote in snakemake as the former offers progress information
rule fetch_igc:
    output: protected(os.path.join(DB_DIR, "igc/igc.fna.gz"))
    log: os.path.join(DB_DIR, "igc/fetch_igc")
    shell:
        """
        (date &&\
        wget ftp://{IGC_URI} -O {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Download HG38 human reference genome
# Downloading using wget-command instead of FTP-remote in snakemake as the former offers progress information
rule fetch_hg38:
    output: protected(os.path.join(DB_DIR, "hg38/GCF_000001405.38_GRCh38.p12_genomic.fna.gz"))
    log: os.path.join(DB_DIR, "hg38/fetch_hg38")
    shell:
        """
        (date &&\
        wget ftp://{HG38_URI} -O {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

rule create_link_to_hg38:
    input: os.path.join(DB_DIR, "hg38/GCF_000001405.38_GRCh38.p12_genomic.fna")
    output: protected(os.path.join(DB_DIR, "hg38/hg38.fna"))
    shell:
        """
        date
        ln -s $(basename -s "" {input}) {output}
        date
        """

rule unpack_reference_data:
    input: os.path.join(DB_DIR, "{prefix}.fna.gz")
    output: protected(os.path.join(DB_DIR, "{prefix}.fna"))
    shell:
        """
        date
        gzip -dc {input} > {output}
        date
        """

# Build a minimap2 index to map *ONT* reads against
rule build_minimap2_ont_index:
    input: "{prefix}.fna"
    output: "{prefix}-ont.mmi"
    log: "{prefix}.minimap2_ont_index"
    conda: "envs/minimap2.yaml"
    shell:
        """
        (date &&\
        minimap2 -x map-ont -d {output} {input} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Build a minimap2 short read index in order to map short reads to a reference/long read-based contigs
# NOTE: Unclear whether this would be also the right option for mapping short reads to long reads (i.e., reads-to-reads), due to the increased error rate in long reads. For more discussions on this, see https://github.com/lh3/minimap2/issues/407#issuecomment-493823000
# TODO: Combine this rule and `build_minimap2_ont_index` using a conditional on the suffix (ont vs. sr). This makes the code more readable as it removes largely redundant `input` and `output` keywords
rule build_minimap2_sr_index:
    input: "{prefix}.fna"
    output: "{prefix}-sr.mmi"
    log: "{prefix}.minimap2_sr_index"
    conda: "envs/minimap2.yaml"
    shell:
        """
        (date &&\
        minimap2 -x sr -d {output} {input} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Build a bwa index (may be used to map short reads against it, or long reads by using the "-x ont2d" flag)
rule build_bwa_index:
    input: "{prefix}.fna"
    output: index_amb="{prefix}.amb",
       index_ann="{prefix}.ann",
       index_bwt="{prefix}.bwt",
       index_pac="{prefix}.pac",
       index_sa="{prefix}.sa"
    log: "{prefix}.bwa_index"
    conda: "envs/bwa.yaml"
    shell:
        """
        (date &&\
        bwa index {input} -p {wildcards.prefix} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Simple utility function
rule convert_fastq_to_fasta:
    input: "{prefix}.fastq.gz"
    output: "{prefix}.fna"
    shell:
        """
        date
        zcat {input} | sed -n '1~4s/^@/>/p;2~4p' > {output}
        date
        """

rule convert_fq_to_fasta:
    input: "{prefix}.fq.gz"
    output: "{prefix}.fna"
    shell:
        """
        date
        zcat {input} | sed -n '1~4s/^@/>/p;2~4p' > {output}
        date
        """

# Map long reads to a reference (IGC/HG38/other). The resulting BAM file can be use for many things, among other to estimate which long reads are "known" or "novel", or to estimate the coverage of reference sequences (regions thereof).
rule map_long_reads_to_reference_w_minimap2:
    input: 
        query=os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fastq.gz"),
        index=os.path.join(DB_DIR, "{reference}/{reference}-ont.mmi"),
        index_fa=os.path.join(DB_DIR, "{reference}/{reference}.fna")
    output: os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}-x-{reference}.bam")
    params:
        prefix=os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}-x-{reference}")
    threads: config["minimap2"]["threads"]
    log: os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}-x-{reference}.minimap2_samtools")
    conda: "envs/minimap2.yaml"
    shell:
        """
        (date &&\
        minimap2 -a -t {threads} {input.index} {input.query} | samtools view -bT {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.prefix} > {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Preprocess the short reads using fastp
rule run_fastp_on_short_reads:
    input:
        r1=os.path.join(config["short_reads_prefix"], "{sr_sample}_R1_001.fastq.gz"),
        r2=os.path.join(config["short_reads_prefix"], "{sr_sample}_R2_001.fastq.gz")
    output:
        r1=os.path.join(RESULTS_DIR, "preprocessing/sr/{sr_sample}_R1_001.fastp.fq.gz"),
        r2=os.path.join(RESULTS_DIR, "preprocessing/sr/{sr_sample}_R2_001.fastp.fq.gz"),
        html=os.path.join(RESULTS_DIR, "preprocessing/sr/{sr_sample}.fastp.html"),
        json=os.path.join(RESULTS_DIR, "preprocessing/sr/{sr_sample}.fastp.json")
    log: os.path.join(RESULTS_DIR, "preprocessing/sr/{sr_sample}.fastp")
    conda: "envs/fastp.yaml"
    shell:
        """
        (date &&\
        fastp -l {config[fastp][min_length]} -i {input.r1} -I {input.r2} -o {output.r1} -O {output.r2} -h {output.html} -j {output.json} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# TODO: Simplify paths by removing the `sr`.
rule run_fastqc_on_preprocessed_short_reads:
    input: os.path.join(RESULTS_DIR, "preprocessing/sr/{sr_sample}_{suffix}.fq.gz"),
    output:
        html=os.path.join(RESULTS_DIR, "qc/sr/fastqc/{sr_sample}/{sr_sample}_{suffix}.fastqc.html"),
        zip=os.path.join(RESULTS_DIR, "qc/sr/fastqc/{sr_sample}/{sr_sample}_{suffix}.fastqc.zip") # the suffix _fastqc.zip is necessary for multiqc to find the file. If not using multiqc, you are free to choose an arbitrary filename
    conda: "envs/fastqc.yaml"
    script: "scripts/run_fastqc.py" # Use a separate script rather than a simple call to FASTQC to overcome possible race conditions when running in parallel (https://bitbucket.org/snakemake/snakemake-wrappers/raw/7f5e01706728e32d52aa413f213e950f50bf4129/bio/fastqc/wrapper.py)

rule map_short_reads_to_reference_w_minimap2:
    input: 
        query_r1=rules.run_fastp_on_short_reads.output.r1,
        query_r2=rules.run_fastp_on_short_reads.output.r2,
        index=os.path.join(DB_DIR, "{reference}/{reference}-sr.mmi"),
        index_fa=os.path.join(DB_DIR, "{reference}/{reference}.fna")
    output: os.path.join(RESULTS_DIR, "mapping/sr/minimap2/{sr_sample}-x-{reference}.bam")
    params:
        prefix=os.path.join(RESULTS_DIR, "mapping/sr/minimap2/{sr_sample}-x-{reference}")
    threads: config["minimap2"]["threads"]
    log: os.path.join(RESULTS_DIR, "mapping/sr/minimap2/{sr_sample}-x-{reference}.minimap2_samtools")
    conda: "envs/minimap2.yaml"
    shell:
        """
        (date &&\
        minimap2 -a -t {threads} {input.index} {input.query_r1} {input.query_r2} | samtools view -@ {config[samtools][view][threads]} -bT {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.prefix} > {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

rule map_short_reads_to_reference_w_bwa_mem:
    input: 
        query_r1=rules.run_fastp_on_short_reads.output.r1,
        query_r2=rules.run_fastp_on_short_reads.output.r2,
        index_amb=os.path.join(DB_DIR, "{reference}/{reference}.amb"),
        index_ann=os.path.join(DB_DIR, "{reference}/{reference}.ann"),
        index_bwt=os.path.join(DB_DIR, "{reference}/{reference}.bwt"),
        index_pac=os.path.join(DB_DIR, "{reference}/{reference}.pac"),
        index_sa=os.path.join(DB_DIR, "{reference}/{reference}.sa"),
        index_fa=os.path.join(DB_DIR, "{reference}/{reference}.fna")
    output: os.path.join(RESULTS_DIR, "mapping/sr/bwa_mem/{sr_sample}-x-{reference}.bam")
    params:
        index_prefix=os.path.join(DB_DIR, "{reference}/{reference}"),
        out_prefix=os.path.join(RESULTS_DIR, "mapping/sr/bwa_mem/{sr_sample}-x-{reference}")
    threads: config["bwa"]["threads"]
    log: os.path.join(RESULTS_DIR, "mapping/sr/bwa_mem/{sr_sample}-x-{reference}.bwa_mem_samtools")
    conda: "envs/bwa.yaml"
    shell:
        """
        (date &&\
        bwa mem -t {threads} {params.index_prefix} {input.query_r1} {input.query_r2} | samtools view -@ {config[samtools][view][threads]} -bT {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.out_prefix} > {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Compute the genome coverage histogram - https://bedtools.readthedocs.io/en/latest/content/tools/genomecov.html
# The resulting histogram is used to compute the expected, i.e., average, coverage of the underyling reference (which may be de novo contigs).
rule run_genomecov:
    input: os.path.join(RESULTS_DIR, "mapping/{prefix}.bam")
    output: os.path.join(RESULTS_DIR, "genomecov/{prefix}.cov.txt")
    conda: "envs/bedtools.yaml"
    shell:
        """
        date
        bedtools genomecov -ibam {input} > {output}
        date
        """

# Compute the expected, i.e., average, coverage given the coverage histogram
rule compute_avg_genomecov:
    input: os.path.join(RESULTS_DIR, "genomecov/{prefix}.cov.txt")
    output: os.path.join(RESULTS_DIR, "genomecov/{prefix}.avg_cov.txt")
    shell:
        """
        date
        cat {input} | awk -f {config[compute_avg_coverage][bin]} | tail -n+2 > {output}
        date
        """

# TODO: All above rules that build an index build it in the same path as the reference/target file
# In fact, it is redundant with `build_bwa_index`. The only advantage is that this replication allows more fine-grained control of the resources (slurm, etc.). This is, however, probably not needed as `build_bwa_index` can be quite resource-intensive, e.g., for the IGC.
# Similar to building a minimap2 index, but this time for bwa
rule build_long_read_bwa_index:
    input: rules.get_single_fastq_per_barcode.output
    output: os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}.amb"),
            os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}.ann"),
            os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}.bwt"),
            os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}.pac"),
            os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}.sa")
    params:
        prefix=os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}")
    log: os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}.bwa_index")
    conda: "envs/bwa.yaml"
    shell:
        """
        (date &&\
        bwa index {input} -p {params.prefix} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """
# TODO: If TODO-build_long_read_bwa_index is completed, need to adjust the `input.index` here too
# config[bwa][long_reads_index][opts] according to https://github.com/sfu-compbio/colormap/blob/baa6802b43da8640c305032b7f7fcadd7c496a03/run_corr.sh#L45 and https://academic.oup.com/bioinformatics/article/32/17/i545/2450793#112481513 -> "2.2.3 Mapping parameters"
rule map_short_reads_to_long_reads:
    input: 
        query_r1=rules.run_fastp_on_short_reads.output.r1,
        query_r2=rules.run_fastp_on_short_reads.output.r2,
        index=os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}.amb"),
        index_fa=os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fna"),
    output: os.path.join(RESULTS_DIR, "mapping/lr/merged/{sr_sample}-x-{barcode}.bam")
    threads: config["bwa"]["threads"] 
    params:
        index_prefix=os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}"),
        out_prefix=os.path.join(RESULTS_DIR, "mapping/lr/merged/{sr_sample}-x-{barcode}.")
    log: os.path.join(RESULTS_DIR, "mapping/lr/merged/{sr_sample}-x-{barcode}.bwa_mem_samtools")
    conda: "envs/bwa.yaml"
    shell:
        """
        (date &&\
        bwa mem {config[bwa][long_reads_index][opts]} -t {threads} {params.index_prefix} {input.query_r1} {input.query_r2} | samtools view -@ {config[samtools][view][threads]} -S -b -u -T {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.out_prefix} > {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# TODO: Add extra rules for other assemblers instead of a generic rule as this offers then greater flexibility, e.g., in terms of resource-reservation.
rule assemble_long_reads_w_flye:
    input: rules.get_single_fastq_per_barcode.output
    output: os.path.join(RESULTS_DIR, "assembly/flye/lr/merged/{barcode}/assembly.fna")
    threads: config["flye"]["threads"]
    log: os.path.join(RESULTS_DIR, "assembly/flye/lr/merged/{barcode}/assembly.flye")
    conda: "envs/flye.yaml"
    shell:
        """
        (date &&\
        flye --nano-raw {input} --meta --out-dir $(dirname {output}) --genome-size {config[flye][genome_size]} --threads {threads} &&\
        ln -s assembly.fasta {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# "r941_min_high" is the MinION model, high accuarcy
rule polish_long_read_contigs_w_medaka:
    input: 
        basecalls=rules.get_single_fastq_per_barcode.output,
        contigs=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.fna")
    output: os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/medaka/round_{round}/lr/merged/{barcode}/assembly_polished.fna")
    threads: config["medaka"]["threads"]
    log: os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/medaka/round_{round}/lr/merged/{barcode}/assembly_polished.medaka")
    conda: "envs/medaka.yaml"
    shell:
        """
        (date &&\
        medaka_consensus -i {input.basecalls} -d {input.contigs} -o $(dirname {output}) -t {threads} -m r941_min_high &&\
        ln -s consensus.fasta {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Having the "initial" explicitly in the rule name is not ideal. However, the path to the original contigs is somewhat variable and hence a discriminative rule name was chosen.
# As piping is no longer supported by racon since v. 1.0.0 (https://github.com/isovic/racon/issues/46#issuecomment-519380742) and the file extensions are checked for all files including the contigs), some temporary files have to be created and removed afterwards.
rule polish_long_read_contigs_w_racon_initial_round:
    input: 
        basecalls=rules.get_single_fastq_per_barcode.output,
        contigs=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.fna"),
        lr_to_lr_contigs_mapping=os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_contigs.bam"),
    output: os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/racon/round_{round}/lr/merged/{barcode}/assembly_polished.fna")
    params:
        tmp_sam=os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/racon/round_{round}/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_contigs.tmp.sam"),
        tmp_contigs=os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/racon/round_{round}/lr/merged/{barcode}/assembly_polished.tmp_draft.fa")
    threads: config["racon"]["threads"]
    log: os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/racon/round_{round}/lr/merged/{barcode}/assembly_polished.racon.log")
    conda: "envs/racon.yaml"
    shell:
        """
        (date &&\
        samtools view -h {input.lr_to_lr_contigs_mapping} > {params.tmp_sam} &&\
        cp {input.contigs} {params.tmp_contigs} &&\
        racon -t {threads} {input.basecalls} {params.tmp_sam} {params.tmp_contigs} > {output} &&\
        rm {params.tmp_sam} {params.tmp_contigs} &&\
        date) 2> >(tee {log}) > >(tee {log})
        """

#polished_contigs=os.path.join(RESULTS_DIR, "assembly/operams/lr_{barcode}-sr_{sr_sample}/contigs.polished.fna")
#ln -s contigs.polished.fasta {output.polished_contigs} &&\
#rule assemble_long_and_short_reads_w_operams:
#    input: 
#        lr=rules.get_single_fastq_per_barcode.output,
#        sr_r1=rules.run_fastp_on_short_reads.output.r1,
#        sr_r2=rules.run_fastp_on_short_reads.output.r2,
#        sr_contigs=os.path.join(RESULTS_DIR, "assembly/megahit/{sr_sample}/final.contigs.fna")
#    output: 
#        contigs=os.path.join(RESULTS_DIR, "assembly/operams/lr_{barcode}-sr_{sr_sample}/contigs.fna")
#    params:
#        tmp_lr=os.path.join(RESULTS_DIR, "assembly/operams/lr_{barcode}-sr_{sr_sample}/tmp_lr_{barcode}.fna")
#    threads: config["operams"]["threads"]
#    log: os.path.join(RESULTS_DIR, "assembly/operams/lr_{barcode}-sr_{sr_sample}/opera_ms.log")
#    shell:
#        """
#        (date &&\
#        zcat {input.lr} > {params.tmp_lr} &&\
#        {config[operams][bin]} --long-read-mapper minimap2 --num-processors {threads} --short-read1 {input.sr_r1} --short-read2 {input.sr_r2} --long-read {params.tmp_lr} --contig-file {input.sr_contigs} --out-dir $(dirname {output.contigs}) &&\
#        ln -s contigs.fasta {output.contigs} &&\
#        rm {params.tmp_lr} &&\
#        date) 2> >(tee {log}) > >(tee {log})
#        """

#zcat {input.lr} > {params.tmp_lr} &&\
rule assemble_long_and_short_reads_w_metaspades:
    input: 
        lr=rules.get_single_fastq_per_barcode.output,
        sr_r1=rules.run_fastp_on_short_reads.output.r1,
        sr_r2=rules.run_fastp_on_short_reads.output.r2,
        sr_contigs=os.path.join(RESULTS_DIR, "assembly/megahit/{sr_sample}/final.contigs.fna")
    output: 
        contigs=os.path.join(RESULTS_DIR, "assembly/metaspades_hybrid/lr_{barcode}-sr_{sr_sample}/contigs.fna")
    params:
        tmp_lr=os.path.join(RESULTS_DIR, "assembly/metaspades_hybrid/lr_{barcode}-sr_{sr_sample}/tmp_lr_{barcode}.fna")
    threads: config["metaspades"]["threads"]
    log: os.path.join(RESULTS_DIR, "assembly/metaspades_hybrid/lr_{barcode}-sr_{sr_sample}/metaspades.log")
    conda: "envs/spades.yaml"
    shell:
        """
        (date &&\
        spades.py --meta -o $(dirname {output.contigs}) -k 21,33,55,77 -t {threads} -1 {input.sr_r1} -2 {input.sr_r2} --nanopore {input.lr} &&\
        ln -s contigs.fasta {output.contigs} &&\
        date) &> >(tee {log})
        """

rule map_short_reads_to_hybrid_contigs_w_bwa_mem:
    input: 
        query_r1=rules.run_fastp_on_short_reads.output.r1,
        query_r2=rules.run_fastp_on_short_reads.output.r2,
        index_amb=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.amb"),
        index_ann=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.ann"),
        index_bwt=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.bwt"),
        index_pac=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.pac"),
        index_sa=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.sa"),
        index_fa=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.fna")
    output: os.path.join(RESULTS_DIR, "mapping/sr/bwa_mem/{sr_sample}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs.bam")
    params:
        index_prefix=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs"),
        out_prefix=os.path.join(RESULTS_DIR, "mapping/sr/bwa_mem/{sr_sample}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs")
    log: os.path.join(RESULTS_DIR, "mapping/sr/bwa_mem/{sr_sample}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs.bwa_mem_samtools")
    conda: "envs/bwa.yaml"
    threads: config["bwa"]["threads"]
    shell:
        """
        (date &&\
        bwa mem -t {threads} {params.index_prefix} {input.query_r1} {input.query_r2} | samtools view -@ {config[samtools][view][threads]} -SbT {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.out_prefix} > {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

rule map_long_reads_to_hybrid_contigs_w_bwa_mem:
    input: 
        query_lr=rules.get_single_fastq_per_barcode.output,
        index_amb=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.amb"),
        index_ann=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.ann"),
        index_bwt=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.bwt"),
        index_pac=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.pac"),
        index_sa=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.sa"),
        index_fa=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs.fna")
    output: os.path.join(RESULTS_DIR, "mapping/lr/bwa_mem/{barcode}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs.bam")
    params:
        index_prefix=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr_{barcode}-sr_{sr_sample}/contigs"),
        out_prefix=os.path.join(RESULTS_DIR, "mapping/lr/bwa_mem/{barcode}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs")
    conda: "envs/bwa.yaml"
    threads: config["bwa"]["threads"]
    log: os.path.join(RESULTS_DIR, "mapping/lr/bwa_mem/{barcode}_reads-x-lr_{barcode}_sr_{sr_sample}-{assembler}_contigs.bwa_mem_samtools")
    shell:
        """
        (date &&\
        bwa mem -x ont2d -t {threads} {params.index_prefix} {input.query_lr} | samtools view -@ {config[samtools][view][threads]} -SbT {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.out_prefix} > {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# rule build_minimap2_long_read_contigs_ont_index:
#     input: os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/{prefix}.fna")
#     output: os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/{prefix}-ont.mmi")
#     conda: "envs/minimap2.yaml"
#     shell:
#         """
#         date
#         minimap2 -x map-ont -d {output} {input}
#         date
#         """

rule map_long_reads_to_long_read_contigs:
    input: 
        query=os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fastq.gz"),
        index=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly-ont.mmi"),
        index_fa=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.fna")
    output: os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_contigs.bam")
    params:
        prefix=os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}_reads-x_{barcode}_contigs")
    conda: "envs/minimap2.yaml"
    threads: config["minimap2"]["threads"]
    log: os.path.join(RESULTS_DIR, "mapping/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_contigs.minimap2_samtools")
    shell:
        """
        (date &&\
        minimap2 -a -t {threads} {input.index} {input.query} | samtools view -@ {config[samtools][view][threads]} -SbT {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.prefix} > {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

rule map_long_reads_to_long_read_polished_contigs:
    input: 
        query=os.path.join(RESULTS_DIR, "basecalled/merged/{barcode}.fastq.gz"),
        index=os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/{polisher}/round_{round}/lr/merged/{barcode}/assembly_polished-ont.mmi"),
        index_fa=os.path.join(RESULTS_DIR, "assembly/{assembler}/polished/{polisher}/round_{round}/lr/merged/{barcode}/assembly_polished.fna")
    output: os.path.join(RESULTS_DIR, "mapping/polished/{polisher}/round_{round}/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_polished_contigs.bam")
    params:
        prefix=os.path.join(RESULTS_DIR, "mapping/polished/{polisher}/round_{round}/lr/merged/{barcode}/{barcode}_reads-x_{barcode}_polished_contigs")
    conda: "envs/minimap2.yaml"
    threads: config["minimap2"]["threads"]
    log: os.path.join(RESULTS_DIR, "mapping/polished/{polisher}/round_{round}/lr/merged/{barcode}/{barcode}_reads-x-{barcode}-{assembler}_polished_contigs.minimap2_samtools")
    shell:
        """
        (date &&\
        minimap2 -a -t {threads} {input.index} {input.query} | samtools view -@ {config[samtools][view][threads]} -SbT {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.prefix} > {output} &&\
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# rule build_minimap2_long_read_contigs_sr_index:
#     input: os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/{prefix}.fna")
#     output: os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/{prefix}-sr.mmi")
#     conda: "envs/minimap2.yaml"
#     shell:
#         """
#         date
#         minimap2 -x sr -d {output} {input}
#         date
#         """

rule map_short_reads_to_long_read_contigs_w_minimap2:
    input: 
        query_r1=rules.run_fastp_on_short_reads.output.r1,
        query_r2=rules.run_fastp_on_short_reads.output.r2,
        index=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly-sr.mmi"),
        index_fa=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.fna")
    output: os.path.join(RESULTS_DIR, "mapping/sr/minimap2/{sr_sample}_reads-x-{barcode}-{assembler}_contigs.bam")
    params:
        prefix=os.path.join(RESULTS_DIR, "mapping/sr/minimap2/{sr_sample}_reads-x_{barcode}_contigs")
    conda: "envs/minimap2.yaml"
    threads: config["minimap2"]["threads"]
    log: os.path.join(RESULTS_DIR, "mapping/sr/minimap2/{sr_sample}_reads-x-{barcode}-{assembler}_contigs.minimap2_samtools")
    shell:
        """
        (date &&\
        minimap2 -a -t {threads} {input.index} {input.query_r1} {input.query_r2} | samtools view -@ {config[samtools][view][threads]} -SbT {input.index_fa} | samtools sort -@ {config[samtools][sort][threads]} -m {config[samtools][sort][chunk_size]} -T {params.prefix} > {output}
        date) 2> >(tee {log}.stderr) > >(tee {log}.stdout)
        """

# Also map the short reads with bwa mem as it might be more sensitive (https://github.com/lh3/minimap2/issues/214#issuecomment-413492006)
rule map_short_reads_to_long_read_contigs_w_bwa_mem:
    input: 
        query_r1=rules.run_fastp_on_short_reads.output.r1,
        query_r2=rules.run_fastp_on_short_reads.output.r2,
        index_amb=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.amb"),
        index_ann=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.ann"),
        index_bwt=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.bwt"),
        index_pac=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.pac"),
        index_sa=os.path.join(RESULTS_DIR, "assembly/{assembler}/lr/merged/{barcode}/assembly.sa"),