manifest {
    name            = 'Eco-Flow/excon'
    author          = 'Chris Wyatt'
    homePage        = 'https://github.com/Eco-Flow/excon'
    description     = 'A pipeline to measure gene family expansion and contraction'
    mainScript      = 'main.nf'
    nextflowVersion = '!>=25.04.6'
    version         = '2.3.1'
}

// Defaults parameters, expecting to be overwritten
params {
  // Core
  outdir                     = "results"
  // Path to input CSV (required unless --input_tree + --input_orthogroups are set and --run_eggnog/--stats are not)
  input                      = null
  // GO enrichment options (apply whichever GO annotation source is used)
  chromo_go                  = null
  go_cutoff                  = 0.05
  go_type                    = "none"
  go_max_plot                = 10
  go_algo                    = "classic_fisher"
  // Limit parallel jobs (useful on small clusters)
  forks                      = null  
  // Remove work directories upon pipeline completion
  clean                      = false
  // Path to a custom Nextflow config file
  custom_config              = null
  // Max resource options
  max_memory                 = '128.GB'
  max_cpus                   =  16
  max_time                   = '48.h'
  // Display help message with nf-validation
  help                       = null
  // nf-core module parameters
  publish_dir_mode           = 'copy'
  // NCBI taxonomic groups to download
  groups                     = 'all'
  // Run stats (QUAST+BUSCO+AGAT)
  stats                      = null
  // BUSCO options
  busco_mode                 = 'proteins'
  busco_lineage              = 'auto'
  busco_lineages_path        = null
  busco_config               = null

  // Pre-computed OrthoFinder inputs (skip the slow OrthoFinder step)
  input_tree                 = null  // path to SpeciesTree_rooted_node_labels.txt (or equivalent rooted Newick tree)
  input_orthogroups          = null  // path to Orthogroups.tsv from a previous OrthoFinder run

  // OrthoFinder version — set to true to use v2.5.5 instead of v3.1.3.
  // v2.5.5 is recommended for large datasets where v3 runs fail or stall.
  orthofinder_v2             = false

  // OrthoFinder algorithm options (null = use OrthoFinder defaults)
  orthofinder_method         = null  // -M: gene tree inference method: 'msa' (default) or 'dendroblast'
  orthofinder_msa_prog       = null  // -A: MSA program (requires -M msa): 'mafft' (default) or 'muscle'
  orthofinder_search         = null  // -S: sequence search program: 'diamond' (default), 'blast', 'mmseqs2'
  orthofinder_tree           = null  // -T: tree inference method (requires -M msa): 'fasttree' (default), 'raxml', 'raxml-ng', 'iqtree'

  // Branch-length scaling factor applied to the OrthoFinder species tree before CAFE5.
  // rescale_tree.py multiplies all branch lengths by this value; chronos() in cafe_prep.R
  // then converts the result to a proper time tree. The default of 1000 works well in
  // most cases — lower values can cause numerical issues in CAFE5.
  tree_scale_factor          = 1000

  // CAFE differential filtering threshold (used on retry after failure)
  // Lower values = more aggressive filtering; recommended: 40 (conservative), 50 (balanced), 60 (lenient)
  skip_cafe                  = null
  cafe_max_differential      = 50
  cafe_max_k                 = 6

  // GO annotation — choose one of the two options below:

  // Option A: run EggNOG-mapper to assign GO terms from scratch
  //   The database is ~45 GB; provide --eggnog_data_dir to avoid re-downloading it every run.
  run_eggnog           = false
  eggnog_data_dir      = null   // path to pre-downloaded EggNOG data directory; downloaded automatically if null
  eggnog_target_taxa   = null   // restrict annotations to orthologs from this NCBI taxon ID and its descendants
  eggnog_tax_scope     = null   // taxonomic scope for OG assignment (e.g. 50557 for Insecta)
  eggnog_evalue        = null   // maximum e-value threshold for sequence matches
  eggnog_score         = null   // minimum bitscore
  eggnog_pident        = null   // minimum percent identity (%)
  eggnog_query_cover   = null   // minimum query coverage (%)
  eggnog_subject_cover = null   // minimum subject coverage (%)

  // Representative species for OG functional annotation summary.
  // Auto-selects the species with the most annotated genes when null.
  eggnog_rep_species = null

  // Option B: supply your own pre-computed gene-to-GO mapping files (skips EggNOG entirely)
  //   Point to a directory containing one file per species named {species_id}.go.txt.
  //   Each file must be a two-column TSV: gene_id<TAB>GO:term, one pair per line.
  predownloaded_gofiles = null
}

plugins {
  // id 'nf-co2footprint@1.2.0'   # was broken so blocked for now.
  id 'nf-schema@2.5.1'
  id 'nf-amazon@2.5.2'
}

def timestamp = new java.util.Date().format( 'yyyy-MM-dd_HH-mm-ss')

co2footprint {
    traceFile   = "${params.outdir}/pipeline_info/co2_emissions/co2footprint_trace_${timestamp}.txt"
    reportFile  = "${params.outdir}/pipeline_info/co2_emissions/co2footprint_report_${timestamp}.html"
    summaryFile  = "${params.outdir}/pipeline_info/co2_emissions/co2footprint_summary_${timestamp}.html"
    ci          = 300
    pue         = 1.4
}

// Load base.config by default for all pipelines
includeConfig 'conf/base.config'

// Load custom config if provided
if (params.custom_config != null) {
   try {
       includeConfig "${params.custom_config}"
    } catch (Exception e) {
       System.err.println("WARNING: Could not load config: ${params.custom_config}")
   }
}

// Select a combination of useful profiles i.e. nextflow run -profile local,docker 
profiles {
  local {
    executor.name            = 'local'
  }
  aws_batch {
    includeConfig 'conf/aws_batch.config'
  }
  //Use Docker as the container management software
  docker {
    docker.enabled           = true
    // Remove docker containers after pipeline completes
    docker.remove            = true
    // Sets user for docker to the user who executes pipeline
    docker.runOptions        = '-u $(id -u):$(id -g)'
    // set registry to quay.io
    docker.registry          = "quay.io"
    // Ensure other container engines are unset
    singularity.enabled      = false
    apptainer.enabled        = false
  }
  singularity {
    singularity.enabled      = true
    // Set where singularity cached images are saved
    singularity.cacheDir     = "singularity/cachedir"
    // set registry to quay.io
    singularity.registry     = "quay.io"
    // Ensure other container engines are unset
    docker.enabled           = false
    apptainer.enabled        = false
  }
  apptainer {
    apptainer.enabled        = true
    // Set where singularity cached images are saved
    apptainer.cacheDir       = "apptainer/cachedir"
    // set registry to quay.io
    apptainer.registry       = "quay.io"
    // Ensure other container engines are unset
    docker.enabled           = false
    singularity.enabled      = false
  }
  conda {
    conda.enabled           = true
    docker.enabled          = false
    singularity.enabled     = false
    podman.enabled          = false
    shifter.enabled         = false
    charliecloud.enabled    = false
    conda.channels          = ['conda-forge', 'bioconda']
    apptainer.enabled       = false
}
  test_small { includeConfig 'conf/test_small.config' }
  test_biomart { includeConfig 'conf/test_biomart.config' }
  test_bacteria { includeConfig 'conf/test_bacteria.config' }
  test_bacteria_postortho { includeConfig 'conf/test_bacteria_postortho.config' }
  test_gffmix { includeConfig 'conf/test_gffmix.config' }
  codespace { includeConfig 'conf/codespace.config' }
  // Local Mac profile: drops -u flag so amd64 containers work under Rosetta on Docker 29+
  mac {
    docker.runOptions = ''
  }

}

// Load nf-core modules config
includeConfig 'conf/modules.config'

// Capture exit codes from upstream processes when piping
process.shell = ['/bin/bash', '-euo', 'pipefail']

// Capturing Nextflow log files into a rsults/pipeline_info directory
timeline {
    enabled = true
    file    = "${params.outdir}/pipeline_info/execution_timeline_${timestamp}.html"
}
report {
    enabled = true
    file    = "${params.outdir}/pipeline_info/execution_report_${timestamp}.html"
}
trace {
    enabled = true
    file    = "${params.outdir}/pipeline_info/execution_trace_${timestamp}.txt"
}
dag {
    enabled = true
    file    = "${params.outdir}/pipeline_info/pipeline_dag_${timestamp}.html"
}

// Ensures work directories and removed when pipeline completes
if (params.clean == true) {
   cleanup = true
}

//Set max forks if parameter provided
if (params.forks) {
   process {
        maxForks = params.forks
   }
}

// Function to ensure that resource requirements don't go beyond a maximum limit
def check_max(obj, type) {
    if (type == 'memory') {
        try {
            if (obj.compareTo(params.max_memory as nextflow.util.MemoryUnit) == 1)
                return params.max_memory as nextflow.util.MemoryUnit
            else
                return obj
        } catch (all) {
            println "   ### ERROR ###   Max memory '${params.max_memory}' is not valid! Using default value: $obj"
            return obj
        }
    } else if (type == 'time') {
        try {
            if (obj.compareTo(params.max_time as nextflow.util.Duration) == 1)
                return params.max_time as nextflow.util.Duration
            else
                return obj
        } catch (all) {
            println "   ### ERROR ###   Max time '${params.max_time}' is not valid! Using default value: $obj"
            return obj
        }
    } else if (type == 'cpus') {
        try {
            return Math.min( obj, params.max_cpus as int )
        } catch (all) {
            println "   ### ERROR ###   Max cpus '${params.max_cpus}' is not valid! Using default value: $obj"
            return obj
        }
    }
}

// Overide config if its supplied with --custom_config:
if (params.custom_config != null) {
    try {
        includeConfig "${params.custom_config}"
    } catch (Exception e) {
        System.err.println("WARNING: Could not load config: ${params.custom_config}")
    }
}
