☰
从串行到 Slurm 集群:AutoDock Vina 批量分子对接调度实践
2026/10/29 16:34:45 网站建设 项目流程

简介:面向生物计算与药物设计方向的学习者及科研人员,这份 Autodock Vina 批量分子对接实践文档围绕 Linux 环境下的对接流程与集群调度展开。内容覆盖 Ubuntu 18.04 上 Open Babel、Autodock Vina 与 MGLTools 的依赖安装与目录规划,受体、配体预处理脚本 prepare_receptor4.py 与 prepare_ligand4.py 的用法,vina.sh 环境变量配置与循环批量对接脚本,以及 conf.txt 参数设定、pdbqt 到 sdf 结果转换等环节;同时介绍 Slurm 的 munge 认证配置、slurm-wlm、slurmd、slurmctld 组件安装与 slurm.conf 关键项的填写思路,帮助读者把单机对接任务迁移到集群上排队运行。包内为 1 份 PDF 文档,压缩包约 1MB,篇幅紧凑,以命令与配置示例为主,适合对照终端逐步复现。已有 5257 人学习,可作为从分子对接入门到批量作业提交的实操参考。

1. 从一份 SDF 到一屏 pdbqt:批量分子对接真正难的是调度

手上有两百个化合物的 SDF,受体只有一个。用 Autodock Vina 做一次分子对接,几十秒到几分钟不等,串行跑完一整天,中途断了还得从头再来。多数人第一次做批量对接都卡在这一步——Vina 本身不难,难的是把它塞进 Slurm 这样的调度系统里,还得保证 N 个节点读同一份受体、同一份 conf,各自写回不同的结果文件而不互相覆盖。这份资源就是干这个的:一套 Ubuntu 18.04 上的完整链路,从 MGLTools、Open Babel 装到 Slurm 三节点分区,把串行脚本一路改成sbatch提交。适合已经跑通过单次对接、准备把规模从十个扩到几百个的人。

2. 工具链落地:Ubuntu 18.04 上把 Vina、MGLTools、Open Babel 装到能跑通

分子对接的前置格式转换全靠三个独立工具:Open Babel 管格式互转,MGLTools 里的prepare_receptor4.py和prepare_ligand4.py管加氢、合并非极性氢、算 Gasteiger 电荷并输出 pdbqt,Vina 只负责最后那步构象搜索。三个工具各有各的依赖,装错一个后面全链崩,所以第一步不是急着解压,而是把依赖项一次装齐。

2.1 依赖项一次装齐,别等编译报错才回头补

sudo apt-get update sudo apt-get install -y \ build-essential \ libxt-dev libglu1-mesa-dev libxmu-dev libxi-dev \ libpng-dev libjpeg-dev libtiff-dev \ csh \ python-tk python-numpy python-dev python-pmw \ openbabel

这串包名看着杂乱,其实分成三组。libxt-dev、libglu1-mesa-dev、libxmu-dev、libxi-dev这一组是 X11 和 OpenGL 的开发头文件,MGLTools 跑install.py时会尝试编译 PMV 图形界面,缺了它们会在编译阶段抛出一堆X11/Intrinsic.h: No such file之类的错误;就算你压根不用图形界面,install.py也不认这个理由。csh是因为 MGLToolsPckgs 里好几个 Utilities24 下的脚本 shebang 写的是#!/bin/csh,Ubuntu 默认不带 csh,最后的表现是"命令明明在 PATH 里却报 not found"。第三组python-tk、python-numpy、python-dev、python-pmw全是为了 Python 2 服务的——MGLTools 1.5.6 只认 Python 2.7,Ubuntu 18.04 的默认python恰好还是 2.7,所以能装;换到 20.04 之后默认python指向 python3,这一步就会直接翻车。

openbabel单独用 apt 装就好,没必要源码编译。对分子对接这个场景,我们只用到 SDF 到 mol2、pdbqt 到 sdf 这几个方向的转换,apt 版本足够。

提示:python-pmw在部分镜像源里已经改名或合并,如果 apt 报找不到,把它从列表里去掉即可,它只影响 PMV 图形界面,不影响prepare_*4.py这批命令行脚本。

2.2 目录规划与解压:tar 参数别照抄

mkdir -p /home/autodock cd /home/autodock # Vina 是静态编译的二进制,解压即用,注意参数顺序 tar -xzf autodock_vina_1_1_2_linux_x86.tgz # MGLTools 是带 python 安装器的打包文件 tar -xzf mgltools_x86_64Linux2_1.5.6.tar_.gz

tar -xvfz这种写法在很多老教程里流传,f 必须紧跟压缩包文件名,-xvfz 包名在某些 tar 版本下会把z当成文件名去读,报"cannot open: No such file"。规范写法是-xzf,解压、gzip、输出信息一次到位。别小看这一行,我第一次照抄就是卡在这里怀疑压缩包损坏。

目录统一放/home/autodock有实际好处:后面 Slurm 的作业脚本里要写三行export PATH,路径固定成绝对路径,比$HOME更省心——sbatch 拉起的作业不保证$HOME和你交互式登录时一致。

解压完的目录结构大致是:

路径内容是否加进 PATH
/home/autodock/autodock_vina_1_1_2_linux_x86/binvina可执行文件是
/home/autodock/MGLTools-1.5.6/binpythonsh等启动器是
/home/autodock/MGLTools-1.5.6/MGLToolsPckgs/AutoDockTools/Utilities24prepare_receptor4.py、prepare_ligand4.py是

2.3 MGLTools 安装与那三行 PATH

cd /home/autodock/MGLTools-1.5.6 ./install.py

install.py会编译少量 C 扩展并把MGLToolsPckgs下的 Python 包注册进去,整个过程大概两三分钟。如果它报找不到python,手动指定python2 install.py也行,效果一样。

装完之后 PATH 三行是整条链路的关键:

export PATH=/home/autodock/autodock_vina_1_1_2_linux_x86/bin/:$PATH export PATH=/home/autodock/MGLTools-1.5.6/bin/:$PATH export PATH=/home/autodock/MGLTools-1.5.6/MGLToolsPckgs/AutoDockTools/Utilities24/:$PATH

三行的顺序其实无所谓,但必须三行都在。只加前两行是最常见的漏配——vina能跑,prepare_ligand4.py却报 command not found,因为它在第三行那个 Utilities24 目录里,而不是bin下。这三行建议直接抄进vina.sh和后面的 SBATCH 脚本里,不要只写进~/.bashrc。原因很简单:sbatch提交的作业由 slurmd 拉起,非交互、不读.bashrc,PATH 里那三个目录全部丢失,作业会在第一个prepare_ligand4.py就退出,而且错误信息只写进job.%j.out,不主动看根本发现不了。

2.4 三条命令验证工具链是通的

# 1. Vina 二进制能否执行 vina --version # 2. 两个预处理脚本是否在 PATH 里 which prepare_receptor4.py prepare_ligand4.py # 3. MGLTools 的 Python 环境是否完整(numpy 最常缺) pythonsh -c "import numpy; print(numpy.__version__)"

第三条容易被跳过。prepare_ligand4.py内部要做坐标运算,numpy 缺失时报的是ImportError: No module named numeric这种含糊信息,很容易被误判成脚本路径问题。pythonsh是 MGLTools 自带的 Python 包装器,用它验证比用系统python更贴近实际执行环境。三条全过,工具链这块就算立住了,可以进入流水线部分。

3. 串行流水线:受体只处理一次,配体按分子循环

整条流水线的骨架是「一次性准备 + 循环体」两段。受体pro.pdb转 pdbqt 只做一次,多分子 SDF 拆分也只在开头做一次,真正进循环的是每个配体单独的prepare_ligand4.py和vina。这个结构决定了后面并行改造的切分方式——切的是循环体,不是准备段。

3.1 受体预处理:-A参数与去水的取舍

# 先看受体里有什么,水分子和杂原子要提前确认 grep -c "^HOH" pro.pdb grep "^HETATM" pro.pdb | awk '{print $4}' | sort -u # 转 pdbqt,-A 控制氢原子处理方式 prepare_receptor4.py -r pro.pdb -A checkhydrogens -o receptor.pdbqt

-A有三个常用取值:hydrogens(默认,合并非极性氢)、checkhydrogens(保留已有氢并检查)、none(不处理氢)。晶体结构通常不带氢,选hydrogens让 MGLTools 自动补;如果是冷冻电镜或者核磁结构、氢位置有实验依据,选checkhydrogens更稳。原始脚本里用的是-e,这个参数在不同 MGLTools 版本里语义不完全一致,跑之前用prepare_receptor4.py -h确认一下当前版本支持什么,比照抄更靠谱。

去水这一步必须显式做。pdbqt 里如果留着结晶水,Vina 的搜索空间会被这些固定原子占掉一部分,打分也会受影响:

grep -v "^HOH" pro.pdb > pro_nowat.pdb prepare_receptor4.py -r pro_nowat.pdb -A hydrogens -o receptor.pdbqt

同理,HETATM里的辅因子、金属离子要不要留,取决于你的结合位点是不是依赖它们。盲目全删和盲目全留都是坑,先看一眼HETATM的残基名再决定。

3.2 配体拆分:obabel -m的命名规则与数量校验

# SDF 转 mol2(一次性) obabel -isd testset.sdf -omol2 -O testset.mol2 # 拆分成单个分子,-m 表示 split mkdir -p mols && cd mols obabel ../testset.mol2 -O vs.mol2 -m # 数量必须和原 SDF 里的分子数对上 ls *.mol2 | wc -l grep -c '\$\$\$\$' ../testset.sdf

-m的命名规则是「输出文件名主干 + 序号 + 扩展名」,所以得到的是vs1.mol2、vs2.mol2……序号从 1 开始。上面两条命令的输出数字必须一致,不一致说明中间有分子转换失败——常见原因是 SDF 里某个分子带价态异常或芳香环标记错误,Open Babel 会跳过它并在 stderr 打警告,但不会中断流程。这个静默丢失非常隐蔽,如果不对数量,你会以为跑了两百个,实际只跑了一百九十几个。

顺手做一次小分子清洗,去掉盐离子和溶剂碎片:

# 小于 10 个重原子的分子大概率是溶剂或离子,不是候选化合物 for f in *.mol2; do n=$(awk '/@<TRIPOS>ATOM/{flag=1;next}/@<TRIPOS>/{flag=0}flag' "$f" | wc -l) if [ "$n" -lt 10 ]; then echo "skip $f ($n atoms)"; rm -f "$f"; fi done

3.3conf.txt:盒子、exhaustiveness 和那个固定不变的 ligand 名

配置文件是整条流水线里唯一被所有配体共享的东西,所以它必须写成「配体文件名固定」的形式:

receptor = receptor.pdbqt ligand = ligand.pdbqt center_x = -12.5 center_y = 8.3 center_z = 24.1 size_x = 22 size_y = 22 size_z = 22 exhaustiveness = 16 num_modes = 9 energy_range = 3 cpu = 1 seed = 20240101

几个参数的实际影响:

参数作用常见取值踩坑点
center_x/y/z搜索盒中心由共晶配体或活性残基质心决定直接填 0,0,0 等于全蛋白盲筛,结果无意义
size_x/y/z盒子边长(Å)20–25小于 18 会切掉部分构象,大于 30 时间暴涨
exhaustiveness搜索强度8(快)/ 16(稳)/ 32(穷举)耗时近似线性增长,批量场景别盲目上 32
num_modes最多输出构象数9设太大只会让后处理变慢
energy_range输出构象的能量窗口(kcal/mol)3设成 0 只保留最优构象
cpu单任务线程数集群里强制 1与 Slurm 的--cpus-per-task不匹配会超配
seed随机种子固定整数不固定则两次结果有微小差异,复现性差

ligand = ligand.pdbqt这个固定名是刻意设计的:循环体里每个配体都被prepare_ligand4.py -o ligand.pdbqt输出成同一个名字,然后vina读同一份 conf,跑完立刻删掉。这样 conf 只需要维护一份,不用在每个循环里sed替换配体名——那是另一条路,但很容易在多线程或并行场景下把 conf 写脏。

盒子的确定方法这里不展开,实操上最省事的是拿共晶配体的坐标算质心:

# 从含共晶配体的 pdb 里取该配体的坐标质心 grep "^HETATM" complex.pdb | awk '$4=="LIG"{sx+=$7;sy+=$8;sz+=$9;n++} END{printf "%.2f %.2f %.2f\n", sx/n, sy/n, sz/n}'

3.4 循环体:vina 输出、pdbqt 转 sdf、结果拼接

cd mols for mol2 in $(ls *.mol2); do # 1. 配体预处理:加氢、合并非极性氢、算电荷 prepare_ligand4.py -l "$mol2" -o ligand.pdbqt # 2. 对接,单线程,输出到固定文件名 vina --config ../conf.txt --cpu 1 --out out.pdbqt --log log.txt # 3. pdbqt 转 sdf 并追加到总结果文件 obabel -ipdbqt out.pdbqt -osd -O temp.sdf cat temp.sdf >> output.sdf # 4. 清理本轮中间文件 rm -f log.txt ligand.pdbqt out.pdbqt temp.sdf done

这段循环有四个点值得说。

第一,prepare_ligand4.py不加参数时默认-A hydrogens,即合并所有非极性氢、只保留极性氢,这正是 Vina 打分函数需要的质子化状态。如果配体里有羧酸、胺基这类可电离基团,而你的靶点口袋对质子化敏感,得先用 Open Babel 在指定 pH 下做质子化,再进这个循环。

第二,vina --cpu 1是刻意压到单线程的。批量场景下如果每个任务都吃 8 线程,节点上并发数立刻被打满,Slurm 的--ntasks-per-node和实际 CPU 占用就对不上了。单任务单线程、靠任务数堆吞吐,是集群上跑分子对接更常见的姿势。

第三,obabel -ipdbqt out.pdbqt -osd这一步转出来的是多构象 SDF,一个配体会产生最多num_modes个模型。cat >> output.sdf直接拼会得到一个巨大的、模型编号重复的文件,后处理时要靠$$$$分隔符重新切开。不少人以为这一步只是格式转换,忽略了这个「一配体多构象」的事实。

第四,rm -f log.txt把唯一的运行日志删了。这是原始脚本里最值得改的一处:一旦某个配体对接失败,你没有任何信息可查,只能重跑。改进方式是每轮把 log 改名保留:

# 用配体名做前缀保留日志和最优构象 vina --config ../conf.txt --cpu 1 --out "out_${mol2%.mol2}.pdbqt" --log "log_${mol2%.mol2}.txt"

改完之后out_*.pdbqt里的REMARK VINA RESULT行就可以直接汇总成打分表,不用再从 SDF 里边转边看。串行跑通一次、确认output.sdf里的构象数和配体数对得上,再往 Slurm 上搬。

4. Slurm 从单机到三节点:munge、四个必改字段和 sbatch 改造

串行脚本跑通之后,并行改造的实质是把「循环遍历配体列表」换成「每个节点领一段列表」。Slurm 负责分发,但前提是三个节点看到的是同一份文件系统、同一套认证密钥、同一份配置文件。这三件事任何一件没对齐,表现出来都是作业莫名卡在 PENDING 或者跑一半退出。

4.1 munge 先起来,认证不通后面全是空转

apt-get install -y make hwloc libhwloc-dev libmunge-dev libmunge2 munge \ mariadb-server libmysqlclient-dev systemctl enable munge systemctl start munge systemctl status munge # 验证 munge 本身能编解码 munge -n | unmunge

最后一条命令的输出里出现STATUS: Success (0)才算通。munge 是 Slurm 的认证底座,slurmctld 和 slurmd 之间所有控制指令都靠它签名。多节点场景下,三个节点的/etc/munge/munge.key必须是同一个文件,且权限是400 munge:munge。这个文件是安装时随机生成的,每台机器都不一样——直接把节点镜像克隆过去反而省事,如果是分别安装,就得手动从控制节点分发:

# 在控制节点上分发,注意权限 scp /etc/munge/munge.key root@node02:/etc/munge/munge.key scp /etc/munge/munge.key root@node03:/etc/munge/munge.key chown munge:munge /etc/munge/munge.key && chmod 400 /etc/munge/munge.key systemctl restart munge

mariadb-server和libmysqlclient-dev是为 Slurm 的记账功能准备的。只做作业调度、不做用量统计的话,AccountingStorageType=accounting_storage/none就够了,这两个包可以不装;但装上了也不影响,属于「留着以后要用」的冗余。

4.2slurm.conf里真正需要改的字段

配置文件在不同发行版里路径不一样,Ubuntu 的 slurm-wlm 包默认读/etc/slurm-llnl/slurm.conf,而不少教程写的是/etc/slurm/slurm.conf。两个路径都存在时以实际slurmd -C和 systemd unit 里--conf-server或-f指定的为准,最稳的确认方式是:

systemctl cat slurmd | grep ExecStart

拿到真实路径后再编辑。下面是三节点场景必须对齐的字段,其余保持注释状态即可:

ClusterName=cluster ControlMachine=node01 ControlAddr=172.28.10.12 SlurmUser=slurm AuthType=auth/munge CryptoType=crypto/munge SlurmctldPidFile=/var/run/slurm-llnl/slurmctld.pid SlurmctldPort=6817 SlurmdPidFile=/var/run/slurm-llnl/slurmd.pid SlurmdPort=6818 SlurmdSpoolDir=/var/lib/slurm-llnl/slurmd StateSaveLocation=/var/lib/slurm-llnl/slurmctld ProctrackType=proctrack/pgid TaskPlugin=task/none MpiDefault=none ReturnToService=1 SchedulerType=sched/backfill SelectType=select/linear SlurmctldDebug=3 SlurmctldLogFile=/var/log/slurm-llnl/slurmctld.log SlurmdDebug=3 SlurmdLogFile=/var/log/slurm-llnl/slurmd.log NodeName=node01 NodeAddr=172.28.10.12 CPUs=1 CoresPerSocket=1 ThreadsPerCore=1 NodeName=node02 NodeAddr=172.28.10.13 CPUs=1 CoresPerSocket=1 ThreadsPerCore=1 NodeName=node03 NodeAddr=172.28.10.14 CPUs=1 CoresPerSocket=1 ThreadsPerCore=1 PartitionName=p1 Nodes=node01 Default=YES MaxTime=INFINITE State=UP PartitionName=p2 Nodes=node02 Default=NO MaxTime=INFINITE State=UP PartitionName=p3 Nodes=node03 Default=NO MaxTime=INFINITE State=UP

几个字段的实际意义:

  • ControlMachine必须是主机名,且三个节点的/etc/hosts里都能解析到;写 IP 在部分版本上会被拒绝。
  • SlurmUser=slurm比root安全,但要提前建好用户并给SlurmdSpoolDir、StateSaveLocation授权。
  • SelectType=select/linear按整节点分配,配置最简单;select/cons_res能按核分配,节点核数多时才值得切。
  • ProctrackType=proctrack/pgid依赖进程组追踪,容器化环境下经常失效,物理机/虚拟机没问题。
  • CPUs=1要和虚拟机的实际核数一致,虚报会导致sbatch --ntasks-per-node=2的作业永远排不上。
  • PartitionName里只能有一个Default=YES,多个分区同时标默认会让 slurmctld 起不来。

配置改完,三个节点的这份文件必须完全一致。Slurm 会对配置做 hash 校验,任何一个节点上的slurm.conf有差异,该节点注册时就会被拒,sinfo里显示为down*或drain。

4.3 目录授权与启动顺序

# 目录要和 slurm.conf 里的路径严格对应 mkdir -p /var/lib/slurm-llnl/slurmd /var/lib/slurm-llnl/slurmctld mkdir -p /var/log/slurm-llnl chown -R slurm:slurm /var/lib/slurm-llnl /var/log/slurm-llnl chmod 755 /var/lib/slurm-llnl/slurmd /var/lib/slurm-llnl/slurmctld # 先起控制节点,再起计算节点 systemctl enable slurmctld slurmd systemctl start slurmctld systemctl start slurmd systemctl status slurmctld --no-pager systemctl status slurmd --no-pager

顺序有讲究:slurmctld 先起,它负责监听 6817;slurmd 起来后主动向控制节点注册,监听 6818。反过来起 slurmd 也能自愈(会重试),但排查阶段先起控制节点能让错误信息更清晰。

SlurmUser=slurm时目录属主必须是slurm;如果沿用SlurmUser=root,不改属主也能跑,但日志和状态文件都会变成 root 所有,后续排查麻烦。这里没有中间路线,选一种贯彻到底。

起来之后的第一条验证命令:

sinfo # 期望看到三个分区,节点状态为 idle scontrol show node node01 # 关注 State 和 RealMemory、CPUTot 是否与实际一致

4.4hostname作业验证 + 把串行脚本改成 SBATCH

先跑最小作业,只验证调度链路:

#!/bin/bash #SBATCH -o job.%j.out #SBATCH -p p1 #SBATCH -J myFirstJob #SBATCH --nodes=1 #SBATCH --ntasks-per-node=1 hostname
sbatch job1.sh squeue -u $USER cat job.*.out

job.%j.out里的%j会被替换成 job id,输出内容应该是node01——如果打出的是提交作业的那台机器名,说明作业压根没被分发出去,回去查sinfo里的分区状态。squeue看到作业从PD变R再消失,job.*.out里有主机名,这条链路才算通。

接着改造对接脚本。并行的核心是「每个分区拿一份自己的配体列表」,所以先把mols切成三份:

#!/bin/bash # 按序号取模切分,1→p1,2→p2,0→p3 cd /home/autodock mkdir -p vina-p1/mols vina-p2/mols vina-p3/mols i=0 for f in mols/*.mol2; do case $((i % 3)) in 1) cp "$f" vina-p1/mols/ ;; 2) cp "$f" vina-p2/mols/ ;; 0) cp "$f" vina-p3/mols/ ;; esac i=$((i + 1)) done

三个目录里各放一份conf.txt和receptor.pdbqt的软链,然后写 SBATCH 脚本:

#!/bin/bash #SBATCH -o job.%j.out #SBATCH -p p1 #SBATCH -J dock_p1 #SBATCH --nodes=1 #SBATCH --ntasks-per-node=1 export PATH=/home/autodock/autodock_vina_1_1_2_linux_x86/bin/:$PATH export PATH=/home/autodock/MGLTools-1.5.6/bin/:$PATH export PATH=/home/autodock/MGLTools-1.5.6/MGLToolsPckgs/AutoDockTools/Utilities24/:$PATH cd /home/autodock/vina-p1/mols for mol2 in $(ls *.mol2); do prepare_ligand4.py -l "$mol2" -o ligand.pdbqt vina --config ../conf.txt --cpu 1 \ --out "out_${mol2%.mol2}.pdbqt" \ --log "log_${mol2%.mol2}.txt" obabel -ipdbqt "out_${mol2%.mol2}.pdbqt" -osd -O "temp_${mol2%.mol2}.sdf" cat "temp_${mol2%.mol2}.sdf" >> output.sdf rm -f "temp_${mol2%.mol2}.sdf" ligand.pdbqt done

三行export PATH一定要写进脚本,这是最容易漏的地方。p1、p2、p3三个脚本只有-p参数和cd路径不同,复制两份改一下即可提交:

sbatch dock_p1.sh sbatch dock_p2.sh sbatch dock_p3.sh squeue -u $USER

5. 五个翻车现场:从 conf 相对路径到 config hash 不一致的排查清单

这套链路我在不同机器上复现过几次,每次翻车的地方都不一样,但错误现象高度集中在下面五类。按「现象 → 原因 → 解决」整理,出问题时对着查比盲猜快得多。

5.1 报Reading ligand ... failed或找不到受体文件

现象:vina在mols/目录下执行,log.txt里写Could not open receptor.pdbqt,但文件明明就在上一级目录。

原因:vina --config读到的receptor和ligand路径,是相对当前工作目录解析的,不是相对conf.txt文件所在目录。脚本先cd mols再执行vina --config ../conf.txt,此时 conf 里的receptor = receptor.pdbqt会被解析成mols/receptor.pdbqt,而文件实际在父目录。

解决:conf 里写receptor = ../receptor.pdbqt,或者干脆全部用绝对路径。绝对路径在多节点、NFS 挂载的场景下更稳,唯一的代价是换机器要改 conf。批量跑的时候建议把这两行单独拎出来做成模板,用sed在部署时替换。

5.2slurmctld起不来,日志里是Invalid partition name或Duplicate default partition

现象:systemctl start slurmctld直接失败,/var/log/slurm-llnl/slurmctld.log里只有一行fatal: Invalid generic configuration,看不出具体字段。

原因:一是多个PartitionName同时写了Default=YES,Slurm 只允许一个默认分区;二是分区引用的Nodes=名字和NodeName=定义不一致,比如Nodes=node1而节点名是node01,这种单复数差异肉眼基本看不出来。

解决:只保留一个Default=YES,其余写Default=NO;用grep -E "^(NodeName|PartitionName)" slurm.conf把两类行拉出来逐字比对。改完先slurmctld -D -vvv前台跑一次,错误会直接打到终端,比翻日志快。

5.3 作业一直 PENDING,Reason=Resources

现象:sbatch提交成功,squeue显示状态PD,Reason列是Resources或PartitionNodeLimit,等到天荒地老也不动。

原因:分区只挂了一个节点,而作业请求的资源超过节点实际配置。最常见的是slurm.conf里CPUs=1,作业却写了--ntasks-per-node=4;或者上一个作业还在R状态没释放,节点被占满。

解决:先scontrol show node node01看CPUTot、AllocTRES和State,确认节点真实核数。虚拟机改过 CPU 数量后必须scontrol update NodeName=node01 State=RESUME让 Slurm 重新读取。批量对接这种单任务单线程的场景,CPUs=1配--ntasks-per-node=1是够用的,别为了「看起来并行」虚报核数。

5.4sinfo里节点显示down*,slurmd 日志报 config hash mismatch

现象:控制节点sinfo能看到三个节点,其中两个是down*,slurmd日志里出现Node ... has a different config hash。

原因:三个节点的slurm.conf内容不一致。哪怕只差一个注释、一个空格,hash 都对不上。另外SlurmdSpoolDir指向的目录不存在时,节点注册也会失败,但报错信息是另一个样子(Spool directory ... does not exist)。

解决:用md5sum /etc/slurm-llnl/slurm.conf在三个节点上各跑一遍,不一致就整个文件覆盖过去,别手工改。目录问题则是对齐slurm.conf里的路径和实际mkdir出来的路径——Ubuntu 打包版的默认路径是/var/lib/slurm-llnl/*,而很多教程里写的是/var/spool/slurm/*,两套都能跑,但必须选一套。

5.5 作业R状态跑了几秒就退出,job.*.out里是prepare_ligand4.py: command not found

现象:交互式登录时手动跑脚本一切正常,sbatch提交就挂,退出码 127。

原因:PATH 配在~/.bashrc里。sbatch拉起的作业是非交互 shell,不加载.bashrc,MGLTools 那三个目录全不在 PATH 里;另外如果脚本是从 Windows 传过来的,行尾是\r\n,shebang 会变成#!/bin/bash\r,报bad interpreter。

解决:把三行export PATH硬写进 SBATCH 脚本开头,不依赖任何 shell 配置文件。行尾问题用file dock_p1.sh确认,出现CRLF就用sed -i 's/\r$//' dock_p1.sh转掉。这两条一起做,基本能消掉「手动能跑、提交就挂」这一类问题。

6. 结果收敛与断点续跑:用 job array 替掉手写分区脚本

手写三份dock_p1.sh、dock_p2.sh、dock_p3.sh能跑,但扩到十个节点就得复制十份,改一个参数要改十次,这是典型的体力活。更规范的做法是用 Slurm 的 job array:一个脚本,一份配体列表,--array控制切分,%控制并发数。

#!/bin/bash #SBATCH -o logs/job.%A_%a.out #SBATCH -J dock_array #SBATCH --nodes=1 #SBATCH --ntasks-per-node=1 #SBATCH --array=0-199%3 export PATH=/home/autodock/autodock_vina_1_1_2_linux_x86/bin/:$PATH export PATH=/home/autodock/MGLTools-1.5.6/bin/:$PATH export PATH=/home/autodock/MGLTools-1.5.6/MGLToolsPckgs/AutoDockTools/Utilities24/:$PATH cd /home/autodock/vina # 用数组下标映射到具体配体,避免多任务抢同一个文件 mapfile -t LIGANDS < <(ls mols/*.mol2 | sort) LIGAND="${LIGANDS[$SLURM_ARRAY_TASK_ID]}" NAME=$(basename "$LIGAND" .mol2) # 断点续跑:已有结果直接跳过,这是后悔药 if [ -s "results/${NAME}.sdf" ]; then echo "skip ${NAME}" exit 0 fi prepare_ligand4.py -l "$LIGAND" -o "tmp/${NAME}.pdbqt" vina --config conf.txt --cpu 1 \ --out "tmp/${NAME}_out.pdbqt" \ --log "logs/${NAME}.log" obabel -ipdbqt "tmp/${NAME}_out.pdbqt" -osd -O "results/${NAME}.sdf" rm -f "tmp/${NAME}.pdbqt" "tmp/${NAME}_out.pdbqt"

--array=0-199%3的意思是展开 200 个任务,同时最多跑 3 个——这个数字应该等于可用节点数乘以每节点能容纳的单线程任务数,不是拍脑袋定的。%A_%a把 array job id 和任务下标都写进日志名,200 个任务各有一份独立日志,某个配体失败时直接看对应文件就行,不用在一个大日志里翻。mapfile那两行是必需的:直接用$SLURM_ARRAY_TASK_ID去索引ls的输出,不同任务在同一时刻ls的顺序理论上一致,但一旦有文件被增删就错位了,先落到数组里再取更稳。

结果汇总不用等全部跑完,中间随时可以看进度和打分分布:

# 已完成数量 ls results/*.sdf 2>/dev/null | wc -l # 从 pdbqt/pdb 里提取最优打分,排序看 Top 20 grep -h "REMARK VINA RESULT" tmp/*_out.pdbqt 2>/dev/null \ | awk '{print $4}' | sort -g | head -20

如果结果文件已经删了中间 pdbqt,就改成从 SDF 的> <minimizedAffinity>字段提取,逻辑一样。真正要注意的是打分不能跨批次直接比:换了seed、换了盒子大小、换了exhaustiveness,同一批分子的分数就不可比。所以我在正式跑之前会把conf.txt的 md5 记在结果目录里,跟results/一起归档。从那以后我每次启动批量对接,都会先跑三个配体做小样本冒烟测试,确认打分和单次手动跑的结果一致,再放开全量——这一步花五分钟,能省掉一整天白跑。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询