Snakemake工作流问题:如何为每行输入生成独立执行命令
问题分析
你当前的规则把所有SMILES条目和输出文件都打包成了单个任务,原因是:
output里用expand生成了所有输出文件,Snakemake将其视为一个任务的多输出- 变量
smiles是整个文件的行列表,在shell命令中会被直接展开为所有字符串的拼接
解决方案
要实现每个SMILES对应一条独立命令,需要用**通配符(wildcard)**拆分任务,让每个任务对应单个输入条目和单个输出文件。修改后的Snakefile如下:
configfile: "config.yaml" # 读取SMILES列表,建立索引到SMILES的映射 smiles = [] with open(config["smiles_file"]) as f: smiles = f.read().splitlines() # 创建索引到SMILES的字典,方便后续通过通配符获取 smiles_dict = {str(i+1): smi for i, smi in enumerate(smiles)} # 定义总目标:生成所有输出文件 rule all: input: expand("results/starting_geometries/{idx}.xyz", idx=smiles_dict.keys()) # 确保输出目录存在 rule make_output_dir: output: directory("results/starting_geometries") shell: "mkdir -p {output}" # 单个SMILES转XYZ的规则,每个任务对应一个条目 rule geometry_from_smiles: input: config["smiles_file"], # 依赖目录创建完成 "results/starting_geometries" output: "results/starting_geometries/{idx}.xyz" params: # 通过通配符{idx}获取对应的SMILES smi=lambda wildcards: smiles_dict[wildcards.idx] shell: "obabel -:'{params.smi}' -oxyz -h --gen3D > {output}"
关键改动说明
rule all:作为整个工作流的入口,定义需要生成的所有目标文件,Snakemake会自动拆分出每个独立任务。- 通配符
{idx}:用索引作为通配符,关联每个任务对应的SMILES条目和输出文件。 smiles_dict:建立索引到SMILES的映射,在rule中通过通配符动态获取当前任务对应的SMILES。make_output_dir:确保输出目录存在,避免shell命令因目录不存在报错。
测试验证
执行dry run(snakemake -n)时,会看到3条独立的命令,每条对应一个SMILES和一个输出文件:
obabel -:'c1ccccc1' -oxyz -h --gen3D > results/starting_geometries/1.xyz obabel -:'Oc1ccccc1' -oxyz -h --gen3D > results/starting_geometries/2.xyz obabel -:'Nc1ccccc1' -oxyz -h --gen3D > results/starting_geometries/3.xyz
内容的提问来源于stack exchange,提问作者Roman
相关产品推荐
相关产品推荐

