在多个群集环境(LSF,SGE)中具有mem_mb资源的Snakemake群集命令

时间:2019-04-19 06:17:34

标签: snakemake

我正在移动在LSF集群中开发的Snakemake工作流程 环境(例如bsub)到SGE集群环境(例如qsub)。 我以前使用 规则中的resources关键字,建议使用变量mem_mbdocs中。我还使用threads关键字指定了我希望可用于该作业的线程数。这些值有时最终会作为我自己的作业的参数(我正在运行的程序允许我指定其最大内存使用量。)

我在转换集群提交时遇到困难 概要文件/脚本对qsub的内存要求的规范, 其中每个作业指定每个核心的内存需求,而bsub则指定每个作业的内存需求。例如,我可能有一个多线程作业,需要64GB内存,并且要在8个内核上运行:

  • 对于bsub,这(基本上)由 bsub -M 65536 -n 8 {...}
  • 对于qsub,我需要指定每个内核的内存(8192): qsub -l h_vmem=8192M -l m_mem_free=8192M -pe smp 8 {...}

过去,我的bsub集群命令将使用这些值 从资源/线程提交作业: snakemake --cluster "bsub -M {resources.mem_mb} -n {threads}"

我希望我可以使用Snakemake的字符串格式进行数学运算: snakemake --cluster "qsub -l h_vmem={resources.mem_mb // threads} -pe smp {threads}"。不幸的是,这不起作用-它告诉我mem_mb // threads不是resources的元素。

我希望能够拥有一个Snakefile,该文件对我的群集环境的影响最小。现在,我正在指定用于完成工作的资源,但这应该相对独立于平台。

是否有一种简单/标准的方法可以解决此差异,我可以应用该方法来提取/计算群集提交命令的此作业信息,而无需添加单独的资源命令?也就是说,我想避免:

# xxx is the memory requirements of the job in MB
mem_mb = xxx
# + 1 to guarantee that mem_mb_per_thread * threads >= mem_mb
mem_mb_per_thread = lambda wc, threads: (xxx // threads) + 1

现在,我期望进入我的Snakefile文件并为特定的集群平台添加一个冗余的resources参数,这似乎是不合适的。这种情况下的最佳做法是什么?

1 个答案:

答案 0 :(得分:0)

答案在Snakemake文档中有点:一个自定义的Snakemake配置文件,以提供一个自定义的Python作业提交脚本。我无法在他们的示例个人资料中找到它,但是在broadinstitute/snakemake-broad-uger上实现了一个很好的示例。此后,我使用jaicher/snakemake-sync-bq-sub处的bsub Snakemake指令为基于qsub--cluster-sync(SGE)的群集实现了一个实现。

在这种情况下,我们可以使用Snakemake辅助函数snakemake.utils.read_job_properties从作业脚本(作业脚本的最后一个参数)中读取作业属性。这使我们能够从作业脚本中提取作业名称,通配符,资源和群集参数,从而可以进行其他处理。因此,最小的解决方案与我想避免的最初想法相距不远:

import sys  # for sys.argv (command-line arguments)
from snakemake.utils import read_job_properties  # to obtain properties

# get path of jobscript
jobscript = sys.argv[-1]
# get job properties
job_info = read_job_properties(jobscript)
# get threads information
threads = job_info.get("threads", 1)
# get resources information
resources = job_info.get("resources", dict())
# get mem_mb information
mem_mb = resources.get("mem_mb", DEFAULT_VALUE)  # define DEFAULT_VALUE elsewhere
mem_mb_per_thread = round(mem_mb / threads, 2)  # memory per thread

# if bsub, resources subcommand is...
bsub_subcmd = f" -M {mem_mb} -n {threads}"

# if qsub, resources subcommand is...
qsub_subcmd = (
    f" -l h_vmem={mem_mb_per_thread}M -l m_mem_free={mem_mb_per_thread}M"
    f" -pe smp {threads}"
)

# run something like `bsub {qsub_subcmd} {other_params} {jobscript}`