/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    nf-core/mag Nextflow base config file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    A 'blank slate' config file, appropriate for general use on most high performance
    compute environments. Assumes that all software is installed and available on
    the PATH. Runs in `local` mode - all jobs will be run on the logged in environment.
----------------------------------------------------------------------------------------
*/

process {

    cpus   = { check_max( 1    * task.attempt, 'cpus'   ) }
    memory = { check_max( 7.GB * task.attempt, 'memory' ) }
    time   = { check_max( 4.h  * task.attempt, 'time'   ) }

    errorStrategy = { task.exitStatus in ((130..145) + 104) ? 'retry' : 'finish' }
    maxRetries    = 3
    maxErrors     = '-1'

    // Process-specific resource requirements
    // NOTE - Please try and re-use the labels below as much as possible.
    //        These labels are used and recognised by default in DSL2 files hosted on nf-core/modules.
    //        If possible, it would be nice to keep the same label naming convention when
    //        adding in your local modules too.
    // See https://www.nextflow.io/docs/latest/config.html#config-process-selectors
    withLabel:process_single {
        cpus   = { check_max( 1                  , 'cpus'    ) }
        memory = { check_max( 6.GB * task.attempt, 'memory'  ) }
        time   = { check_max( 4.h  * task.attempt, 'time'    ) }
    }
    withLabel:process_low {
        cpus   = { check_max( 2     * task.attempt, 'cpus'    ) }
        memory = { check_max( 12.GB * task.attempt, 'memory'  ) }
        time   = { check_max( 4.h   * task.attempt, 'time'    ) }
    }
    withLabel:process_medium {
        cpus   = { check_max( 6     * task.attempt, 'cpus'    ) }
        memory = { check_max( 36.GB * task.attempt, 'memory'  ) }
        time   = { check_max( 8.h   * task.attempt, 'time'    ) }
    }
    withLabel:process_high {
        cpus   = { check_max( 12    * task.attempt, 'cpus'    ) }
        memory = { check_max( 72.GB * task.attempt, 'memory'  ) }
        time   = { check_max( 16.h  * task.attempt, 'time'    ) }
    }
    withLabel:process_long {
        time   = { check_max( 20.h  * task.attempt, 'time'    ) }
    }
    withLabel:process_high_memory {
        memory = { check_max( 200.GB * task.attempt, 'memory' ) }
    }
    withLabel:error_ignore {
        errorStrategy = 'ignore'
    }
    withLabel:error_retry {
        errorStrategy = 'retry'
        maxRetries    = 2
    }

    withName:CUSTOM_DUMPSOFTWAREVERSIONS {
        cache = false
    }

    withName: BOWTIE2_HOST_REMOVAL_BUILD {
        cpus   = { check_max (10    * task.attempt, 'cpus'   ) }
        memory = { check_max (20.GB * task.attempt, 'memory' ) }
        time   = { check_max (4.h   * task.attempt, 'time'   ) }
    }
    withName: BOWTIE2_HOST_REMOVAL_ALIGN {
        cpus   = { check_max (10    * task.attempt, 'cpus'   ) }
        memory = { check_max (10.GB * task.attempt, 'memory' ) }
        time   = { check_max (6.h   * task.attempt, 'time'   ) }
    }
    withName: BOWTIE2_PHIX_REMOVAL_ALIGN {
        cpus   = { check_max (4    * task.attempt, 'cpus'   ) }
        memory = { check_max (8.GB * task.attempt, 'memory' ) }
        time   = { check_max (6.h  * task.attempt, 'time'   ) }
    }
    withName: PORECHOP {
        cpus   = { check_max (4     * task.attempt, 'cpus'   ) }
        memory = { check_max (30.GB * task.attempt, 'memory' ) }
        time   = { check_max (4.h   * task.attempt, 'time'   ) }
    }
    withName: NANOLYSE {
        cpus   = { check_max (2     * task.attempt, 'cpus'   ) }
        memory = { check_max (10.GB * task.attempt, 'memory' ) }
        time   = { check_max (3.h   * task.attempt, 'time'   ) }
    }
    //filtlong: exponential increase of memory and time with attempts
    withName: FILTLONG {
        cpus   = { check_max (8     * task.attempt         , 'cpus'   ) }
        memory = { check_max (64.GB * (2**(task.attempt-1)), 'memory' ) }
        time   = { check_max (24.h  * (2**(task.attempt-1)), 'time'   ) }
    }
    withName: CENTRIFUGE {
        cpus   = { check_max (8     * task.attempt, 'cpus'   ) }
        memory = { check_max (40.GB * task.attempt, 'memory' ) }
        time   = { check_max (12.h  * task.attempt, 'time'   ) }
    }
    withName: KRAKEN2 {
        cpus   = { check_max (8     * task.attempt, 'cpus'   ) }
        memory = { check_max (40.GB * task.attempt, 'memory' ) }
        time   = { check_max (12.h  * task.attempt, 'time'   ) }
    }
    withName: KRONA {
        cpus   = { check_max (8     * task.attempt, 'cpus'   ) }
        memory = { check_max (20.GB * task.attempt, 'memory' ) }
        time   = { check_max (12.h  * task.attempt, 'time'   ) }
    }
    withName: CAT_DB_GENERATE {
        memory = { check_max (200.GB * task.attempt, 'memory' ) }
        time   = { check_max (16.h   * task.attempt, 'time'   ) }
    }
    withName: CAT {
        cpus   = { check_max (8     * task.attempt, 'cpus'   ) }
        memory = { check_max (40.GB * task.attempt, 'memory' ) }
        time   = { check_max (12.h  * task.attempt, 'time'   ) }
    }
    withName: GTDBTK_CLASSIFYWF {
        cpus   = { check_max (10     * task.attempt, 'cpus'   ) }
        memory = { check_max (128.GB * task.attempt, 'memory' ) }
        time   = { check_max (12.h   * task.attempt, 'time'   ) }
    }
    //MEGAHIT returns exit code 250 when running out of memory
    withName: MEGAHIT {
        cpus          = { check_megahit_cpus (8, task.attempt  ) }
        memory        = { check_max (40.GB * task.attempt, 'memory' ) }
        time          = { check_max (16.h  * task.attempt, 'time'   ) }
        errorStrategy = { task.exitStatus in [143,137,104,134,139,250] ? 'retry' : 'finish' }
    }
    //SPAdes returns error(1) if it runs out of memory (and for other reasons as well...)!
    //exponential increase of memory and time with attempts, keep number of threads to enable reproducibility
    withName: SPADES {
        cpus          = { check_spades_cpus (10, task.attempt) }
        memory        = { check_max (64.GB * (2**(task.attempt-1)), 'memory' ) }
        time          = { check_max (24.h  * (2**(task.attempt-1)), 'time'   ) }
        errorStrategy = { task.exitStatus in [143,137,21,1] ? 'retry' : 'finish' }
        maxRetries    = 5
    }
    withName: SPADESHYBRID {
        cpus          = { check_spadeshybrid_cpus (10, task.attempt) }
        memory        = { check_max (64.GB * (2**(task.attempt-1)), 'memory' ) }
        time          = { check_max (24.h  * (2**(task.attempt-1)), 'time'   ) }
        errorStrategy = { task.exitStatus in [143,137,21,1] ? 'retry' : 'finish' }
        maxRetries    = 5
    }
    //returns exit code 247 when running out of memory
    withName: BOWTIE2_ASSEMBLY_ALIGN {
        cpus          = { check_max (2    * task.attempt, 'cpus'   ) }
        memory        = { check_max (8.GB * task.attempt, 'memory' ) }
        time          = { check_max (8.h  * task.attempt, 'time'   ) }
        errorStrategy = { task.exitStatus in [143,137,104,134,139,247] ? 'retry' : 'finish' }
    }
    withName: METABAT2_METABAT2 {
        cpus   = { check_max (8     * task.attempt, 'cpus'   ) }
        memory = { check_max (20.GB * task.attempt, 'memory' ) }
        time   = { check_max (8.h   * task.attempt, 'time'   ) }
    }
    withName: MAG_DEPTHS {
        memory = { check_max (16.GB * task.attempt, 'memory' ) }
    }
    withName: BUSCO {
        cpus   = { check_max (8     * task.attempt, 'cpus'   ) }
        memory = { check_max (20.GB * task.attempt, 'memory' ) }
    }

    withName: MAXBIN2 {
        // often fails when insufficient information, so we allow it to gracefully fail without failing the pipeline
        errorStrategy = { task.exitStatus in [ 1, 255 ] ? 'ignore' : 'retry' }
    }

    withName: DASTOOL_DASTOOL {
        // if SCGs not found, bins cannot be assigned and DAS_tool will die with exit status 1
        errorStrategy = { task.exitStatus in [143,137,104,134,139] ? 'retry' : task.exitStatus == 1 ? 'ignore' : 'finish' }
    }
}
