计算化学公社

标题: 分享个宏展开程序 [打印本页]

作者
Author:
万里云    时间: 2016-8-23 17:38
标题: 分享个宏展开程序
本帖最后由 万里云 于 2016-9-15 20:43 编辑

=======================================================================================
9月15日更新:
发现自己还是孤陋寡闻了,类Unix系统中有一个非常有名的宏展开程序m4,Brian Kernighan 和 Dennis Ritchie这两位鼻祖级人物写的。看了一些有关这个程序的介绍,觉得功能太过强大,用起来也必须小心翼翼。还是继续用我自己写的simple & stupid程序的吧。


修正一个BUG:之前的程序有一个严重的BUG,比如定义了两个宏KPT和KPT_SCF,然后某段文本中有一处KPT_SCF的引用,展开的时候会先把KPT_SCF中的KPT替换掉,剩下那个_SCF在风中凌乱。新版本的程序用比较笨的方法解决了这个问题:所有使用宏的地方必须加一对尖括号(例如<KPT_SCF>)。这样修改可以明确指定哪一部分要展开哪一部分原样不动,避免了潜在的纰漏(宏展开就是个深坑),也能使用foo = <foo>这样的句子了。


增加一条特性:宏之间可以彼此引用,比如先#define a 123,再#define b <a>456这样的。但是这样做时会输出Warning,提醒用户。
(, 下载次数 Times of downloads: 0)


=======================================================================================
不知道各位有没有遇到这种情形:算某个体系需要准备一大堆输入文件,这些输入文件共享一部分设置,每个文件又有自己独有的设置;而另一个体系输入文件与这个体系相差不大,几乎就是变量重新赋值。

我最近就遇到了这种情形,手头有项工作需要计算10个类似的体系,每个体系7个输入文件,各文件间共享原子坐标等信息。一开始纯手工操作,不过这活真不是人干的。尽管vim有很强大的剪贴板(寄存器)功能,但是要保持这么多输入文件一致,还是很耗精力的一件事。一不留神就会把上一个体系的内容贴进来,写完之后还得一步步检查。简直是我等强迫症患者的噩梦。写了十几个输入文件之后,突然觉得这简直是浪费生命。经过仔细分析,手工操作有这么几项不合理之处:




根据“宁花机器一分,不花程序员一秒”的原则,这种事肯定要丢给机器去做。这种俯拾皆是的日常问题,当初搞Unix系统的大牛们肯定也遇到过,肯定已经写好了应对的程序。然而找了一圈,并没有找到。sed好像可以做到,但是学习成本有点高。cpp处理单行的宏还可以,遇到多行的宏就抓瞎了。


只好自己写一个了。好在原理并不复杂,核心算法就是把多行的宏视作含有很多"\n"的单行,宏展开用的是replace函数。




语法规则:

语法和关键字是直接从C/C++语言中的宏定义语句魔改过来的。关键字只有#define和#include两个。


#define有两种用法,第一种是定义只包含一个单词的宏,其格式为#define 宏名 宏内容。这种用法一般适用于"flag = _MACRO"或者"flag _MACRO"这种场合。


第二中用法是定义包含很多行的宏,其格式为#define 宏名,从下一行开始为宏内容,以空白行结束。这种用法一般用于在不同文件中共享大段内容。


如果要共享的内容太多,直接用#define定义非常不方便,这时就需要魔改版的#include出马。#include的用法为#include 宏名 文件名,顾名思义就是把这个文件的内容定义成宏。


例:
下面举个例子。首先准备好宏定义文件defs.h:
  1. #define _PREFIX '7'

  2. #define _DP1
  3.     tefield          = .TRUE.
  4.     dipfield         = .TRUE.

  5. #define _NTYP 2
  6. #define _NAT 11
  7. #define _ECUTWFC 60

  8. #define _DP2
  9.     edir             = 3
  10.     emaxpos          = 0.90
  11.     eopreg           = 0.05
  12.     eamp             = 0.0

  13. #define _NBND 139
  14. #define _NBNDQ 31
  15. #define _NBND_FI 36

  16. #define _POS
  17. ATOMIC_SPECIES
  18.    A  1.00   A.pbe-mt_fhi.UPF
  19.    B  2.00   B.pbe-mt_fhi.UPF
  20. CELL_PARAMETERS {alat}
  21.    4.189217464   0.000000000   0.000000000
  22.    0.000000000   6.366494695   0.000000000
  23.    0.000000000   0.000000000  20.000000000
  24. ATOMIC_POSITIONS {crystal}
  25.    B   0.406112372   0.169055518   0.590080889
  26.    B   0.415434560   0.420296557   0.460720554
  27.    B   0.795080133   0.657181106   0.438815945
  28.    B   0.791784062   0.926322272   0.563877606
  29.    A   0.702046531   0.847801065   0.489021700
  30.    A   0.828305019   0.764721124   0.615770853
  31.    A   0.106950716   0.567103165   0.477558897
  32.    A   0.371472351   0.251891403   0.412202884
  33.    A   0.506322370   0.356770124   0.537003974
  34.    A   0.113144641   0.058345927   0.546460360
  35.    A   0.822827246   0.710861738   0.368446338

  36. #include _KPT ../share/wfn.out
  37. #include _KPTQ ../share/wfnq.out
  38. #include _KPT_FI ../share/wfn_fi.out

  39. // p2b.in
  40. #define _NK1 8
  41. #define _NK2 6
  42. #define _NK3 1
  43. #define _DK1 0
  44. #define _DK2 0
  45. #define _DK3 0
  46. #define _XC_MIN 1
  47. #define _XC_MAX 96

  48. // p2bq.in
  49. #define _DK1Q 0.008
  50. #define _DK2Q 0
  51. #define _DK3Q 0

  52. // p2b_fi.in
  53. #define _NK1_FI 16
  54. #define _NK2_FI 12
  55. #define _NK3_FI 1
复制代码


上面这个文件就是宏定义文件。里面有PREFIX这样的只有一个单词的宏,也有像_POS这样多行的,也有像_KPT这样由文件定义的。


在输入文件模板bands.h中的适当部分引用这些宏:
  1. #
  2. # Input Template for Calculation 'bands'
  3. #
  4. # Version: 1.0.0
  5. #
  6. # Notes:
  7. #
  8. # (1) This file applies for periodic systems only.
  9. #
  10. # (2) The built-in Bravis lattice types are rather unconvenient.
  11. #     So we set ibrav to 0, celldm(1) to 1.8897, and specify the
  12. #     coordinates of lattice vectors in ANGSTROMS under card
  13. #     'CELL_PARAMETERS {alat}'.
  14. #
  15. # (3) 'cg' style diagonalization is more stable than 'david'
  16. #     when nbnd is large. It is the default setting for generating
  17. #     wave functions for BGW.
  18. #
  19. &CONTROL
  20.     prefix           = _PREFIX
  21.     calculation      = 'bands'
  22.     restart_mode     = 'from_scratch'
  23.     pseudo_dir       = './'
  24.     outdir           = './'
  25.     wfcdir           = './'
  26.     verbosity        = 'high'
  27.     wf_collect       = .TRUE.
  28. _DP1
  29. /
  30. &SYSTEM
  31.     ibrav            = 0
  32.     celldm(1)        = 1.889726125
  33.     ntyp             = _NTYP
  34.     nat              = _NAT
  35.     ecutwfc          = _ECUTWFC
  36.     nbnd             = _NBND
  37. _DP2
  38. /
  39. &ELECTRONS
  40.     electron_maxstep = 250
  41.     conv_thr         = 1.0d-10
  42.     mixing_mode      = 'plain'
  43.     mixing_beta      = 0.7
  44.     mixing_ndim      = 8
  45.     diagonalization  = 'cg'
  46.     diago_full_acc   = .TRUE.
  47.     startingwfc      = 'random'
  48. /
  49. _POS
  50. _KPT
复制代码



再运行程序 ./mace.py def.h bands.h bands.in,就生成了输入文件bands.in,其中的宏已经被全部展开:
  1. #
  2. # Input Template for Calculation 'bands'
  3. #
  4. # Version: 1.0.0
  5. #
  6. # Notes:
  7. #
  8. # (1) This file applies for periodic systems only.
  9. #
  10. # (2) The built-in Bravis lattice types are rather unconvenient.
  11. #     So we set ibrav to 0, celldm(1) to 1.8897, and specify the
  12. #     coordinates of lattice vectors in ANGSTROMS under card
  13. #     'CELL_PARAMETERS {alat}'.
  14. #
  15. # (3) 'cg' style diagonalization is more stable than 'david'
  16. #     when nbnd is large. It is the default setting for generating
  17. #     wave functions for BGW.
  18. #
  19. &CONTROL
  20.     prefix           = '7'
  21.     calculation      = 'bands'
  22.     restart_mode     = 'from_scratch'
  23.     pseudo_dir       = './'
  24.     outdir           = './'
  25.     wfcdir           = './'
  26.     verbosity        = 'high'
  27.     wf_collect       = .TRUE.
  28.     tefield          = .TRUE.
  29.     dipfield         = .TRUE.

  30. /
  31. &SYSTEM
  32.     ibrav            = 0
  33.     celldm(1)        = 1.889726125
  34.     ntyp             = 2
  35.     nat              = 11
  36.     ecutwfc          = 60
  37.     nbnd             = 139
  38.     edir             = 3
  39.     emaxpos          = 0.90
  40.     eopreg           = 0.05
  41.     eamp             = 0.0

  42. /
  43. &ELECTRONS
  44.     electron_maxstep = 250
  45.     conv_thr         = 1.0d-10
  46.     mixing_mode      = 'plain'
  47.     mixing_beta      = 0.7
  48.     mixing_ndim      = 8
  49.     diagonalization  = 'cg'
  50.     diago_full_acc   = .TRUE.
  51.     startingwfc      = 'random'
  52. /
  53. ATOMIC_SPECIES
  54.    A  1.00   A.pbe-mt_fhi.UPF
  55.    B  2.00   B.pbe-mt_fhi.UPF
  56. CELL_PARAMETERS {alat}
  57.    4.189217464   0.000000000   0.000000000
  58.    0.000000000   6.366494695   0.000000000
  59.    0.000000000   0.000000000  20.000000000
  60. ATOMIC_POSITIONS {crystal}
  61.    B   0.406112372   0.169055518   0.590080889
  62.    B   0.415434560   0.420296557   0.460720554
  63.    B   0.795080133   0.657181106   0.438815945
  64.    B   0.791784062   0.926322272   0.563877606
  65.    A   0.702046531   0.847801065   0.489021700
  66.    A   0.828305019   0.764721124   0.615770853
  67.    A   0.106950716   0.567103165   0.477558897
  68.    A   0.371472351   0.251891403   0.412202884
  69.    A   0.506322370   0.356770124   0.537003974
  70.    A   0.113144641   0.058345927   0.546460360
  71.    A   0.822827246   0.710861738   0.368446338

  72. K_POINTS crystal
  73.    48
  74.   0.000000000  0.000000000  0.000000000   1.0
  75.   0.000000000  0.166666667  0.000000000   1.0
  76.   0.000000000  0.333333333  0.000000000   1.0
  77.   0.000000000  0.500000000  0.000000000   1.0
  78.   0.000000000  0.666666667  0.000000000   1.0
  79.   0.000000000  0.833333333  0.000000000   1.0
  80.   0.125000000  0.000000000  0.000000000   1.0
  81.   0.125000000  0.166666667  0.000000000   1.0
  82.   0.125000000  0.333333333  0.000000000   1.0
  83.   0.125000000  0.500000000  0.000000000   1.0
  84.   0.125000000  0.666666667  0.000000000   1.0
  85.   0.125000000  0.833333333  0.000000000   1.0
  86.   0.250000000  0.000000000  0.000000000   1.0
  87.   0.250000000  0.166666667  0.000000000   1.0
  88.   0.250000000  0.333333333  0.000000000   1.0
  89.   0.250000000  0.500000000  0.000000000   1.0
  90.   0.250000000  0.666666667  0.000000000   1.0
  91.   0.250000000  0.833333333  0.000000000   1.0
  92.   0.375000000  0.000000000  0.000000000   1.0
  93.   0.375000000  0.166666667  0.000000000   1.0
  94.   0.375000000  0.333333333  0.000000000   1.0
  95.   0.375000000  0.500000000  0.000000000   1.0
  96.   0.375000000  0.666666667  0.000000000   1.0
  97.   0.375000000  0.833333333  0.000000000   1.0
  98.   0.500000000  0.000000000  0.000000000   1.0
  99.   0.500000000  0.166666667  0.000000000   1.0
  100.   0.500000000  0.333333333  0.000000000   1.0
  101.   0.500000000  0.500000000  0.000000000   1.0
  102.   0.500000000  0.666666667  0.000000000   1.0
  103.   0.500000000  0.833333333  0.000000000   1.0
  104.   0.625000000  0.000000000  0.000000000   1.0
  105.   0.625000000  0.166666667  0.000000000   1.0
  106.   0.625000000  0.333333333  0.000000000   1.0
  107.   0.625000000  0.500000000  0.000000000   1.0
  108.   0.625000000  0.666666667  0.000000000   1.0
  109.   0.625000000  0.833333333  0.000000000   1.0
  110.   0.750000000  0.000000000  0.000000000   1.0
  111.   0.750000000  0.166666667  0.000000000   1.0
  112.   0.750000000  0.333333333  0.000000000   1.0
  113.   0.750000000  0.500000000  0.000000000   1.0
  114.   0.750000000  0.666666667  0.000000000   1.0
  115.   0.750000000  0.833333333  0.000000000   1.0
  116.   0.875000000  0.000000000  0.000000000   1.0
  117.   0.875000000  0.166666667  0.000000000   1.0
  118.   0.875000000  0.333333333  0.000000000   1.0
  119.   0.875000000  0.500000000  0.000000000   1.0
  120.   0.875000000  0.666666667  0.000000000   1.0
  121.   0.875000000  0.833333333  0.000000000   1.0

复制代码


以后只需要准备好宏定义文件和输入文件模板,用程序把宏展开就能得到对应的输入文件。原来耗时二十多分钟的任务现在只要不到五分钟。换个体系,需要修改的也只有宏定义文件。更重要的是散布在各文件中的参数现在集中在一个文件中,再也不用担心眼花了。


程序肯定不完善。比如包含多行内容的宏必须以空白行结束定义,这会在生成的文件中引入多余的空行。好在空行多数情况下无关紧要。





欢迎光临 计算化学公社 (http://bbs.keinsci.com/) Powered by Discuz! X3.3