目录

POSCAR固定原子

misaraty 更新 | 2025-07-22
前言
  • 使用 VASP 进行界面或表面结构弛豫时,常常需要按z坐标范围固定部分原子,如何操作呢?

  • 下载示例

POSCAR

我们以CsPbCl3结构为例,在Vesta中查看并选取需要固定的原子z坐标范围(0~0.16)。

结构对应的POSCAR,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
CsPbCl3
1.0
       33.6300010681         0.0000000000         0.0000000000
        0.0000000000        33.6300010681         0.0000000000
        0.0000000000         0.0000000000        58.0250015259
   Cl   Cs   Pb
  576  216  180
Direct
     0.000000000         0.083329998         0.094520003
     0.000000000         0.083329998         0.191110000
     0.000000000         0.083329998         0.287710011
     0.000000000         0.083329998         0.384310007
     0.000000000         0.083329998         0.480899990
     0.083329998         0.000000000         0.094520003
	 ...

运行脚本

 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
82
import os
os.chdir(os.path.split(os.path.realpath(__file__))[0])
print('copyright by Zhaosheng Zhang (misaraty@163.com)\n' + 'last update: 2025-07-22\n')

# ======== Parameter Settings ========
zmin = 0.0  # Minimum fractional z-coordinate to fix
zmax = 0.16  # Maximum fractional z-coordinate to fix
input_path = "POSCAR"
output_path = "POSCAR_sd"
# ====================================

def normalise_frac(z):
    """Normalize a fractional coordinate to the range [0, 1)."""
    while z < 0.0:
        z += 1.0
    while z >= 1.0:
        z -= 1.0
    return z

def process_poscar(lines, zmin, zmax):
    """
    Process POSCAR assuming:
    - No 'Selective Dynamics' present
    - Line 7 is 'Direct'
    - Coordinates start from line 8
    """
    header = lines[:8]
    natoms_list = list(map(int, header[6].split()))
    total_atoms = sum(natoms_list)

    coord_mode_idx = 7            # Line index of 'Direct'
    coord_start_idx = 8           # Coordinates start from line 8 (index 8)
    coord_end_idx = coord_start_idx + total_atoms
    coords = lines[coord_start_idx:coord_end_idx]

    processed = []
    count_fixed = 0

    for line in coords:
        parts = line.strip().split()
        if len(parts) < 3:
            continue
        try:
            z = normalise_frac(float(parts[2]))
        except ValueError:
            continue
        if zmin <= z <= zmax:
            tag = ["F", "F", "F"]
            count_fixed += 1
        else:
            tag = ["T", "T", "T"]
        # Preserve original formatting
        new_line = f"{'  '.join(parts[:3])}  {tag[0]} {tag[1]} {tag[2]}\n"
        processed.append(new_line)

    # Compose output lines
    new_lines = header[:7]
    new_lines.append("Selective Dynamics\n")
    new_lines.append(lines[coord_mode_idx])  # 'Direct'
    new_lines.extend(processed)
    if coord_end_idx < len(lines):
        new_lines.extend(lines[coord_end_idx:])  # Keep comments or blank lines

    # Print stats
    percent = 100.0 * count_fixed / total_atoms
    print(f"✅ Process completed.")
    print(f"Total atoms: {total_atoms}")
    print(f"Fixed atoms: {count_fixed}")
    print(f"Fixed fraction: {percent:.2f}%")

    return new_lines

# === Main execution ===
with open(input_path, 'r') as f:
    lines = f.readlines()

new_lines = process_poscar(lines, zmin, zmax)

with open(output_path, 'w') as f:
    f.writelines(new_lines)

print(f"Modified POSCAR saved to: {output_path}")
注意
运行前需要修改脚本中的zmin = 0.0zmax = 0.16参数。

修改后POSCAR

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
CsPbCl3
1.0
       33.6300010681         0.0000000000         0.0000000000
        0.0000000000        33.6300010681         0.0000000000
        0.0000000000         0.0000000000        58.0250015259
   Cl   Cs   Pb
  576  216  180
Selective Dynamics
Direct
0.000000000  0.083329998  0.094520003  F F F
0.000000000  0.083329998  0.191110000  T T T
0.000000000  0.083329998  0.287710011  T T T
0.000000000  0.083329998  0.384310007  T T T
0.000000000  0.083329998  0.480899990  T T T
0.083329998  0.000000000  0.094520003  F F F
...