一些小脚本来提高工作效率(一)

一些小脚本来提高工作效率(一)

近期需要批处理一些文件,所以这里把这里用到的脚本贴上来总结一下。

MS中的xsd格式文件快速转换为POSCAR文件perl脚本

首先是Material Studio的转换文件格式的一个脚本,可以直接在MS中将xsd格式的文件转换为POSCAR文件,可以减少MS导出cif再转到vesta中的这一个步骤,而且会保留原子是否固定的信息,就可以不再用vaspkit折腾一遍了,这个其实是很早之前抄的武汉理工大学首席教授赵焱写的脚本,不过他的这个脚本在转换时始终会保留原子的固定与否的信息,所以对我现在不需要保留的时候使用就会有点不方便,

所以经过我的一番尝试之后,我删去了一些不必要的注释,对内部的代码进行了一定程度上的修改,然后加了一些我写的注释,现在这个脚本在开始的时候可以对变量Fix进行设定,如果设定为Yes则会输出固定原子的信息,如果设定为No则会直接将其转化为POSCAR文件,不保留固定原子的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#!perl
#This is perl script for converting the Materials Studio xsd file to the POSCAR file for VASP.
#xsd2pos.pl can read the constraints information from the xsd file, and write the constraints to the POSCAR file.
#Usage: Change the $filename variable to your xsd file, and it will generate a POSCAR.txt file in the VASP input format. You may copy and paste the text in POSCAR.txt to your POSCAR file.

use strict;
use Getopt::Long;
use MaterialsScript qw(:all);

# Input the file name without suffix.
my $filename = "4N_epoxy1";

# Input whether fix atoms, if you fixed, input Yes, or set it as No.
my $Fix = "No";
my $doc = $Documents{"$filename.xsd"};
my $pos = Documents->New("POSCAR.txt");
my $lattice = $doc->SymmetryDefinition;
my $FT;
my @num_atom;
my @element;
my $ele;
my $num;

$pos->Append(sprintf "$filename \n");
$pos->Append(sprintf "1.0 \n");
$pos->Append(sprintf "%f %f %f \n",$lattice->VectorA->X, $lattice->VectorA->Y, $lattice->VectorA->Z);
$pos->Append(sprintf "%f %f %f \n",$lattice->VectorB->X, $lattice->VectorB->Y, $lattice->VectorB->Z);
$pos->Append(sprintf "%f %f %f \n",$lattice->VectorC->X, $lattice->VectorC->Y, $lattice->VectorC->Z);
my $atoms = $doc->UnitCell->Atoms;

my @sortedAt = sort {$a->AtomicNumber <=> $b->AtomicNumber} @$atoms;

my $count_el=0;
my $count_atom = 0;
$element[0]=$sortedAt[0]->ElementSymbol;
my $atom_num = $sortedAt[0]->AtomicNumber;
foreach my $atom (@sortedAt) {
if ($atom->AtomicNumber == $atom_num) {
$count_atom=$count_atom+1;
} else {
$num_atom[$count_el] = $count_atom;
$count_atom = 1;
$count_el = $count_el+1;
$element[$count_el]=$atom->ElementSymbol;
$atom_num = $atom->AtomicNumber;
}
}
$num_atom[$count_el] = $count_atom;

foreach $ele (@element) {
$pos->Append(sprintf "$ele ");
}
$pos->Append(sprintf "\n");

foreach $num (@num_atom) {
$pos->Append(sprintf "$num ");
}
$pos->Append(sprintf "\n");

if ($Fix eq "Yes"){
$pos->Append(sprintf "Selective Dynamics\nDirect \n");
foreach my $atom (@sortedAt) {
if ($atom->IsFixed("XYZ")) {
$FT = "F F F";
} elsif ($atom->IsFixed("FractionalXYZ")) {
$FT = "F F F";
} else {
$FT = "T T T";
}
$pos->Append(sprintf "%f %f %f %s \n", $atom->FractionalXYZ->X, $atom->FractionalXYZ->Y, $atom->FractionalXYZ->Z, $FT);
}
} elsif($Fix eq "No"){
$pos->Append(sprintf "Direct \n");
foreach my $atom (@sortedAt){
$pos->Append(sprintf "%f %f %f %s \n", $atom->FractionalXYZ->X, $atom->FractionalXYZ->Y, $atom->FractionalXYZ->Z);
}
} else {
$pos->Append(sprintf "WRONG!!!!\n DO NOT SET THE RIGHT FIX!\n PLEASE CHECK THE VALUE OF FIX!!!!!");
}


用法的话也很简单,直接在MS里面创建一个文件,如xsd.pl,然后将上面的代码复制进去,在最开始将要转换的文件名输入进去(无需xsd的文件名后缀),然后点debug即可以转换格式,注意,文件需要跟pl文件在同一个目录下。


自动创建文件夹并配置POTCAR,自动提交任务的bash脚本

其实看到上一步接下来就知道我下一步需要干嘛了,我要将如此多个文件转移到服务器上,然后分别创建文件夹,配置INCAR,POTCAR以及KPOINTS,再全部提交任务,这些工作一次提交还好,但是全部提交的确是有点折腾人,所以我打算写一个bash脚本来一次性全部处理,从创建文件到提交任务,一条龙服务。

这里列举一下我在写这个脚本的时候遇到的问题:

Bash中变量的引用与设置

首先是bash中的变量定义以及应用,在定义变量的时候=左右都不能有空格,然后就是要记得分场合看是否需要加引号,这里有个问题就是,如果文件名里面有空格的话,在将文件名用作变量的时候就会出问题,因为空格会导致你传输出来的变量被分开,从而导致无法正确的处理文件。

sed提取数据中无法去掉的空格

接下来说说我在写POTCAR文件配置的时候遇到的问题,这里我打算留一个输入口,即指定一下赝势文件所在的位置,然后再自动识别POSCAR生成POTCAR文件,以下是代码实现的部分:

1
2
3
4
5
6
7
8
9
 #!/bin/bash

#指定你的赝势库存储的位置
POT_file=~/PAW_PBE
elements=$(sed -n 6p POSCAR)
for i in $elements
do
cat $POT_file/$i/POTCAR >> POTCAR
done

这就是一个简单的生成POTCAR的脚本,自动读取POSCAR中第六行的元素,然后按照顺序往POTCAR中添加赝势文件,原理并不难,但是在应用中出现了一个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
[jason@cabc1 1N3O]$ for i in $elements; do cat "$POT_file"/$i/POTCAR >> POTCAR; done
/POTCAR: No such file or directory

#根据上面的报错可以看出是目录有问题,那么看看elements这个变量里面有些啥
[jason@cabc1 1N3O]$ for i in $elements; do cat $POT_file/$i/POTCAR >> POTCAR; echo $i; done
C
N
O
Mn
/POTCAR: No such file or directory

[jason@cabc1 1N3O]$

为了方便看出情况,我把最后输入一栏也复制了过来,可以看到,第六行导出的元素还多了一个空白格,这个空白格目前来看既不是空集也不是空格,我没能够用if语句把它去掉,后面我也尝试过用sed的通配符去除,但是也失败了。

1
2
3
4
5
6
7
8
9
[jason@cabc1 1N3O]$ elements=$(sed -n 6p POSCAR | sed 's/[:space:]*$//g')
[jason@cabc1 1N3O]$ for i in $elements ; do echo $i; done
C
N
O
Mn

[jason@cabc1 1N3O]$

所以这里我选择了一个相对来说比较笨的办法,直接忽略掉最后一个元素,不让它进入循环,弄到这里其实也只是为了满足强迫症罢了,因为即使它报错也不会影响生成的赝势文件。

1
2
3
4
5
6
7
[jason@cabc1 1N3O]$ for i in ${elements%?} ; do  echo $i; done
C
N
O
Mn
[jason@cabc1 1N3O]$

很难想象这么简单一个问题我花了这么长时间去解决,最后也只获得了一个勉强能接受的结果。

文件名中的空格

这里我还遇到个问题,就是文件名的空格,我在MS中用上面的perl脚本生成的POSCAR文件,在自动命名的过程中它会在中间生成空格,这导致我在使用脚本的时候遇到了一些问题,我想了很多办法来解决这个问题,比如最常用的rename 方法,但是实际应用中无法修改文件名中的空格

具体的原因我也没能够查明,后面我决定直接忽略这个问题,将直接带有空格的文件名加个引号传个mv指令,将其在移动到对应文件的过程中直接改名为POSCAR

1
2
3
4
5
6
7
8
9
#!/bin/bash

count=0
for i in *.txt
do
count=$(($count+1))
mkdir $count
mv "$i" $count/POSCAR
done

最终稿的脚本

鼓捣了好长时间,终于是写出来一个勉强可以用的bash脚本,这个脚本目前仅仅能支持自动将目录下的所有POSCAR.txt文件分配到不同的文件并为它们量身指定POTCAR文件,再将目录下提前写好的KPOINTS、INCAR和提交任务的脚本(我的是vasp.sh)复制到每个文件中,再用sbatch指令提交任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash

#This script can help you process a batch of POSCAR files, it could automatically assign folders and create corresponding pseudopotential files, and copy the INCAR, KPOINTS and the mission-sub file to the folders, and sub the calculate mission.
#Remember To Modify your own pseudopotential file location!
#This script is using sbatch order to sub mission!
#If your own server do not user sbatch order, remember change it!
#Last Modified in 20230207 By Phoenix Jason Wang, DUT

POTCAR_file=~/PAW_PBE
mission_sub_file=vasp.sh
mission_sub_order=sbatch

count=0
for i in *.txt
do
count=$(($count+1))
echo $count
mkdir $count
mv "$i" $count/POSCAR

# Generate the INCAR file
cp INCAR $count
#sed -i '/MAGMOM/s/*/MAGMOM = /g' INCAR

# Generate the KPOINTS file
cp KPOINTS $count

# Inpuut the sub file
cp $mission_sub_file $count

cd $count
# Generate the POTCAR file
elements=$(sed -n 6p POSCAR)
for element in ${elements%?}
do
cat $POTCAR_file/$element/POTCAR >> POTCAR
done

# Sub the caculate mission, check your sever do use this order!
$mission_sub_order $mission_sub_file
cd ..

done

感觉这个脚本还是要有一定的bash语言基础才能弄得懂的,我描述也不好写太多了,就先这样吧,其实可以看到,它可以自动生成POTCAR文件,但是对于INCAR以及KPOINTS文件还没办法生成,然后其实提交任务这个指令也是可以直接整合到里面的,这些都是可以进一步改进的,以后我鼓捣出更加完整的脚本了我就再写一篇博文发出来吧。接下来放张图,看一下这个脚本的实际运行效果:

脚本能够正常运行,感觉还是能够节省不少时间的。


一些小脚本来提高工作效率(一)
http://phoenixjason.cn/2023/02/07/20230207一些小脚本来提高工作效率(一)/
作者
Jason
发布于
2023年2月7日
许可协议