process {
  // Default resources for components that hardly do any processing
  memory = { 2.GB * task.attempt }
  cpus = 1

  // Retry for exit codes that have something to do with memory issues
  errorStrategy = { task.exitStatus in 137..140 ? 'retry' : 'terminate' }
  maxRetries = 3
  maxMemory = null

  // Resource labels
  withLabel: singlecpu { cpus = 1 }
  withLabel: lowcpu { cpus = 2 }
  withLabel: midcpu { cpus = 4 }
  withLabel: highcpu { cpus = 8 }
  withLabel: veryhighcpu { cpus = 16 }
 
  withLabel: lowmem { memory = { get_memory( 4.GB * task.attempt ) } }
  withLabel: midmem { memory = { get_memory( 16.GB * task.attempt ) } }
  withLabel: highmem { memory = { get_memory( 24.GB * task.attempt ) } }
  withLabel: veryhighmem { memory = { get_memory( 48.GB * task.attempt ) } }
}

def get_memory(to_compare) {
  if (!process.containsKey("maxMemory") || !process.maxMemory) {
    return to_compare
  }

  try {
    if (process.containsKey("maxRetries") && process.maxRetries && task.attempt == (process.maxRetries as int)) {
      return process.maxMemory
    }
    else if (to_compare.compareTo(process.maxMemory as nextflow.util.MemoryUnit) == 1) {
      return max_memory as nextflow.util.MemoryUnit
    }
    else {
      return to_compare
    }
  } catch (all) {
        println "Error processing memory resources. Please check that process.maxMemory '${process.maxMemory}' and process.maxRetries '${process.maxRetries}' are valid!"
        System.exit(1)
  }
}

