||
在研究中,经常需要对一系列体系执行相同的计算任务。常见的例子比如考察不同外场对某种性质的影响,或者计算同一反应在不同衬底上的能垒。因为同一批次计算任务的输入文件大同小异,有人就偷懒会直接复制上一次的输入文件,最多略作修改。但要准确无误地记住修改哪些参数,并在繁杂的输入文件中找到这些参数还是很费事的,一不小心还会出错。时间久了,总会有那么几次忘记修改某个关键参数,白白浪费掉宝贵的工作时间和机时。出过几次差错之后,有人就会想到准备一套模板,里面关键的参数先空着,用时再视情况填入具体的值。模板在某种程度上避免了忘记修改某个参数,但也只是解决了一部分问题。准备输入文件的过程中棘手之处还有很多:
① 不少计算任务包含多步计算,每一步都有相应的输入文件,给分散在多个输入文件中的大量参数赋值依然费时费力。虽然UltraEdit、Vim等文本编辑器的剪贴板功能非常强大,可以加快填写速度,但同时也提高了因为张冠李戴而出错的几率。一旦换个体系,又得从头重新来一边,重复劳动太多。
② 不同输入文件中的参数可能不独立,比如参数a在文件A和B之中取值必须相同,而文件B中的参数b取值必须是A中的千分之一。这些依赖关系会显著增加工作量和出错几率。
以用GW+BSE方法研究材料光学性质为例。BerkeyGW是一个专门用于GW+BSE计算的软件,功能强大,但非常复杂。一套计算流程下来,仅DFT环节就需要五步共九个输入文件,GW+BSE环节还需要四步共四个输入文件。这些输入文件中不仅许多参数相互关联,有的参数还需要用另外的程序生成,而这些程序本身也需要输入文件,总之用起来非常麻烦。
DFT环节分为01-scf、02-wfn、03-wfnq、04-wfn_path和05-wfn_fi五步。01-scf需要一个输入文件scf.in,其余四步每一步都需要两个输入文件bands.in和p2b.in。Scf.in和bands.in中各参数依赖关系如下图所示:
图中蓝色部分圈出的参数取值必须相同,而红色部分内的参数取值不同。该图只给出了01-scf/scf.in、02-wfn/bands.in和03-wfnq/bands.in中参数依赖关系,04-wfn_path/bands.in和05-wfn_fi/bands.in与之类似。
上图所示输入文件中最后一部分为K点设置。除01-scf/scf.in之外,bands.in中的K点均需用kgrid.x生成(wfn.out),而kgrid.x又需要输入文件(wfn.inp),wfn.inp中K点设置还需要和p2b.in保持一致。参数依赖关系如下图所示(以02-wfn为例):
02-wfn、03-wfnq、05-wfn_fi三步计算的wfn.inp之间还需要满足如下依赖关系:
不知道各位看到这里被绕晕了没有,这简直就是吾等强迫症患者的噩梦。以前每次准备输入文件,都要照着规则一条一条去检查,没半个小时根本弄不完。后来有一项工作需要准备十几组输入文件,我终于受够了这个枯燥且繁琐的过程,决定弄个程序,一劳永逸地解决这个问题。这个程序必须有如下几个功能:
① 能够自动给模板中的参数赋值,方法是宏展开;
② 把散落在多个模板中的参数集中在一个文件中管理,免去四处寻找之苦;
③ 如果两个参数间存在依赖关系,那这种依赖关系应该由程序计算而非手算;
④ 能够把另一个文件中的内容包含进模板,类似C/C++语言中的#include预处理指令;
既然核心算法是宏展开,首先想到的程序就是C/C++预处理器cpp。但这个程序只支持单行宏定义,且不支持数学计算。后来了解到宏处理器m4,但这个程序比较艰深晦涩,对数学计算的支持也不是很完美。最后决定用Python自己写一个宏处理器。核心算法是字符串递归替换,因此主程序(mace.py)非常简单:
使用时只需编写一个脚本(run_mace.py)调用main函数即可。调用main函数需要三个参数:存储宏定义的字典macro,模板文件名template和生成的输入文件名output。除main函数外,还提供了一个include函数,用于把指定文件中的内容包含进模板。include函数除文件名filename外,另有两个可选参数nl0和nl1用于指定行号,即可以只包含从开始行到结束行的内容(含这两行)。行号从1开始,nl0默认为第一行,nl1默认为最后一行。run_mace.py示例如下:
在脚本第2行导入了mace模块中的main函数和include函数,然后创建一个字典m并向其中添加宏定义。键名就是宏名,键值就是宏的值。宏可以是整数(NTYP和NAT)、浮点数(ECUTWFC)、单行字符串(PREFIX)和多行字符串(DP1、DP2、POS),也可以是一个文件中的内容(KPT)。如果两个宏之间存在依赖关系,也可以直接写进去,例如第14行指定ECUTRHO必须为 ECUTWFC的4倍。在脚本最后调用mace模块的main函数,所用模板为当前目录下的scf.tpl,所生成的输入文件为当前目录下的test.in。我们来看一下模板(scf.tpl)中的内容:
模板中凡是需要填入数值的参数后面都加了宏引用,并用尖括号标注出来。运行脚本run_mace.py即可将这些宏引用替换为设定的值,所生成的test.in内容如下:
由图可知,所有模板中的宏引用都被替换成了run_mace.py中设定的值。如果需要生成多个输入文件,在run_mace.py中循环调用main函数即可。
上面的例子仅用于示范程序的用法,没多少实际意义。接下来给两个实用性较强的例子,首先是生成不同晶格常数下的石墨烯POSCAR。这种操作在优化晶体结构时很常见,所用模板(POSCAR.tpl)如下:
脚本(run_mace.py)如下:
运行脚本即可产生POSCAR.2.46、POSCAR.2.47和POSCAR.2.48,其中一个内容如下:
第二个例子是生成BerkeleyGW输入文件。这个例子的脚本(share/gen_inp.py)比较长,首先定义02-wfn、03-wfnq和05-wfn_fi三步计算所需K点的相关设置,调用run_kgrid函数生成K点:
然后定义模板中所需的宏,其中最复杂的K点设置由程序自动计算,再调用copy_upf函数复制赝势到相关目录,最后调用run_mace函数生成输入文件:
所生成输入文件的内容在第一节已经给出了,这里不再赘述。
用宏处理器生成输入文件,只需在第一次时花点时间准备好模板和脚本,后面修改脚本即可,输入文件可以由程序自动生成。即使某个参数设置有误,再次生成输入文件也很简单。相比于以前每次都得几十分钟的工作量,可以说是一劳永逸了。
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-11-24 03:57
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社