本脚本能够从单个 POSCAR 出发,自动完成常压优化、压力点序列生成、结构迭代、能带与声子谱后处理的全流程。实现了从结构对称性分析到计算结果后处理的完整闭环,适用于需要批量处理高压计算任务的体系。
需提起配置好VASPKIT与PHONOPY环境。
本文将详细介绍该脚本的设计思路、使用方法与注意事项,
准备文件:仅需准备POSCAR
操作流程
$ sh db-4.sh
[INFO] 2026-03-18 01:03:25 ===== 基础文件检查 =====
[INFO] 2026-03-18 01:03:25 校验K点设置...
[INFO] 2026-03-18 01:03:25 ✅ K点设置合理:444 0 0
[INFO] 2026-03-18 01:03:25 ===== INCAR参数配置 =====
是否设置磁性?(y/n,默认n):n
是否取消对称性?(y/n,默认n):n
是否增加截断能?(y/n,默认n):n
自定义优化精度?(y/n,默认n,格式:1E-08;-2E-02):y
输入EDIFF;EDIFFG:1E-05;-2E-01
添加NCORE?(y/n,默认n):y
NCORE值:4
添加范德华修正?(y/n,默认n):n
VASP运行命令(示例:mpirun -np 32 vasp_std,默认:mpirun -np 16 vasp_std):mpirun -np 32 vasp_std-w
[INFO] 2026-03-18 01:04:05 ✅ VASP命令:mpirun -np 32 vasp_std-w
[INFO] 2026-03-18 01:04:05 ===== 初始结构设置 =====
是否跳过常压(0GPa)优化?(y/n,默认n):n
[INFO] 2026-03-18 01:04:18 ===== 常压(0GPa)结构优化 =====
[INFO] 2026-03-18 01:04:18 ✅ 初始空间群:International: Fm-3m
[INFO] 2026-03-18 01:04:18 第1次常压优化...



完成初次常压结构优化(或可指定初始结构)后,可设置压力梯度与计算要求。
[INFO] 2026-03-18 00:51:07 ✅ 已选择已有CONTCAR作为初始输入:CONTCAR
[INFO] 2026-03-18 00:51:07 ✅ 初始空间群(基于已有CONTCAR):International: Fm-3m
[INFO] 2026-03-18 00:51:07 ===== 压力梯度设置 =====
压力输入类型:
1) 特殊压力点(如:1 5 10 GPa)
2) 常压至最大值(如:0-80GPa,自动步长)
3) 分段压力(如:0-30,70-200GPa)
选择类型(1/2/3,默认1):1
输入压力点(空格分隔):1 55
[INFO] 2026-03-18 00:51:32 最终压力列表(从小到大):1 55 GPa
[INFO] 2026-03-18 00:51:32 ===== 物性计算设置 =====
是否计算能带?(y/n,默认n):y
指定能带INCAR?(y/n,默认n):
是否使用原胞进行能带计算?(y/n,默认n):y
[INFO] 2026-03-18 00:51:40 ✅ 启用原胞进行能带计算
[INFO] 2026-03-18 00:51:40 生成KPATH.in(vaspkit -task 303)
+---------------------------------------------------------------+
| VASPKIT Standard Edition 1.5.1 (27 Jan. 2024) |
| Running VASPKIT Under Command-Line Mode |
+---------------------------------------------------------------+
+-------------------------- Summary ----------------------------+
Prototype: AB
Total Atoms in Input Cell: 8
Lattice Constants in Input Cell: 6.411 6.411 6.411
Lattice Angles in Input Cell: 90.000 90.000 90.000
Total Atoms in Primitive Cell: 2
Lattice Constants in Primitive Cell: 4.534 4.534 4.534
Lattice Angles in Primitive Cell: 60.000 60.000 60.000
Crystal System: Cubic
Crystal Class: m-3m
Bravais Lattice: cF
Extended Bravais Lattice: cF2
Space Group Number: 225
Point Group: 32 [ Oh ]
International: Fm-3m
Symmetry Operations: 192
Suggested K-Path: (shown in the next line)
[ GAMMA-X-U|K-GAMMA-L-W-X ]
+---------------------------------------------------------------+
-->> (01) Written HIGH_SYMMETRY_POINTS File for Reference.
-->> (02) Written PRIMCELL.vasp file.
-->> (03) Written KPATH.in File for Band-Structure Calculation.
o----------------------------WARNING----------------------------o
| Do NOT forget to copy PRIMCELL.vasp to POSCAR unless you know |
| what you are doing. Otherwise you might get wrong results! |
o---------------------------------------------------------------o
+---------------------------- Tip ------------------------------+
| Make sure you have installed python & matplotlib successfully.|
| The plot utility is under development in the preview release. |
| You CAN custom plot parameters in PLOT.in file if it exists, |
| or in ~/.vaspkit file if the PLOT.in file does NOT found. |
+---------------------------------------------------------------+
-->> (04) Reading Plot Setting from the PLOT.in File.
findfont: Font family 'arial' not found.
fin
-->> (05) Written Brillouin_Zone_3D.jpg File.
|---------------------------------------------------------------|
| * CITATIONS * |
| When using VASPKIT in your research PLEASE cite the paper: |
| [1] V. WANG, N. XU, J.-C. LIU, G. TANG, W.-T. GENG, VASPKIT: A|
| User-Friendly Interface Facilitating High-Throughput Computing|
| and Analysis Using VASP Code, Computer Physics Communications |
| 267, 108033, (2021), DOI: 10.1016/j.cpc.2021.108033 |
o---------------------------------------------------------------o
[INFO] 2026-03-18 00:51:43 当前KPATH.in内容:
K-Path Generated by VASPKIT.
20
Line-Mode
Reciprocal
0.0000000000 0.0000000000 0.0000000000 GAMMA
0.5000000000 0.0000000000 0.5000000000 X
0.5000000000 0.0000000000 0.5000000000 X
0.6250000000 0.2500000000 0.6250000000 U
0.3750000000 0.3750000000 0.7500000000 K
0.0000000000 0.0000000000 0.0000000000 GAMMA
0.0000000000 0.0000000000 0.0000000000 GAMMA
0.5000000000 0.5000000000 0.5000000000 L
0.5000000000 0.5000000000 0.5000000000 L
0.5000000000 0.2500000000 0.7500000000 W
0.5000000000 0.2500000000 0.7500000000 W
0.5000000000 0.0000000000 0.5000000000 X
确认KPATH.in是否合适?(y/n,默认y):y
是否计算声子谱?(y/n,默认n):y
指定声子INCAR?(y/n,默认n):
[INFO] 2026-03-18 00:51:47 ===== 开始压力循环计算 =====
[INFO] 2026-03-18 00:51:47 ===== 处理压力点:1 GPa(文件夹:P1GPa) =====
[INFO] 2026-03-18 00:51:47 ✅ 设置PSTRESS=10 kB(1 GPa)
[INFO] 2026-03-18 00:51:47 第1次优化1 GPa结构...
完整脚本附:
#!/bin/bash
set -uo pipefail
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 日志函数
log() { echo -e "${BLUE}[INFO] $(date +%Y-%m-%d\ %H:%M:%S) $1${NC}"; }
error() { echo -e "${RED}[ERROR] $(date +%Y-%m-%d\ %H:%M:%S) $1${NC}"; exit 1; }
warning() { echo -e "${YELLOW}[WARNING] $(date +%Y-%m-%d\ %H:%M:%S) $1${NC}"; }
# 检查命令是否存在
check_command() {
if ! command -v "$1" &> /dev/null; then
error "命令$1未找到,请先安装并配置环境变量!"
fi
}
# 检查文件是否为非空白
check_non_empty_file() {
local file=$1
if [ ! -f "$file" ] || [ ! -s "$file" ]; then
return 1
fi
return 0
}
# 核心函数:提取空间群
get_space_group() {
local poscar_file=$1
if ! check_non_empty_file "$poscar_file"; then
echo "UNKNOWN"
return
fi
# 临时复制POSCAR到当前目录执行601
cp "$poscar_file" TMP_POSCAR
mv POSCAR POSCAR_BAK 2>/dev/null
mv TMP_POSCAR POSCAR
# 执行601并提取International空间群
space_group=$(vaspkit -task 601 2>&1 | grep "International:" | awk '{print $2}')
# 恢复原POSCAR
mv POSCAR_BAK POSCAR 2>/dev/null
rm -f TMP_POSCAR
[ -z "$space_group" ] && space_group="UNKNOWN"
echo "$space_group"
}
# ===================== 第一步:基础文件检查与修复 =====================
log "===== 基础文件检查 ====="
# 2. 自动生成KPOINTS(缺失/过小)
if ! check_non_empty_file "KPOINTS"; then
warning "未找到有效KPOINTS,自动生成..."
(echo 102; echo 2; echo 0.04) | vaspkit
fi
# 3. 修正K点校验(核心:提取第4行)
log "校验K点设置..."
kmesh_line=$(sed -n '4p' KPOINTS | awk '{print $1, $2, $3}' | tr -d ' ' | awk '{for(i=1;i<=3;i++) printf "%.0f ", $i}')
k1=$(echo $kmesh_line | awk '{print $1}')
k2=$(echo $kmesh_line | awk '{print $2}')
k3=$(echo $kmesh_line | awk '{print $3}')
if [ "$k1" -eq 1 ] && [ "$k2" -eq 1 ] && [ "$k3" -eq 1 ]; then
warning "K点过小(1x1x1),自动更新..."
(echo 102; echo 2; echo 0.04) | vaspkit
kmesh_line=$(sed -n '4p' KPOINTS | awk '{print $1, $2, $3}')
fi
log "✅ K点设置合理:$kmesh_line"
# 1. 检查核心文件(仅检查INCAR/POTCAR,POSCAR可选,因为可能用已有CONTCAR)
if ! check_non_empty_file "INCAR"; then error "INCAR文件不存在或为空!"; fi
if ! check_non_empty_file "POTCAR"; then error "POTCAR文件不存在或为空(需手动从VASP官网获取)!"; fi
# ===================== 第二步:INCAR参数配置 =====================
log "===== INCAR参数配置 ====="
cp INCAR INCAR.bak
# 1. 磁性设置
read -p "是否设置磁性?(y/n,默认n):" is_mag; is_mag=${is_mag:-n}
sed -i '/ISPIN/d' INCAR
echo "ISPIN = $( [ "$is_mag" = "y" ] && echo 2 || echo 1 )" >> INCAR
[ "$is_mag" = "y" ] && warning "已设ISPIN=2,请手动添加MAGMOM!"
# 2. 对称性设置
read -p "是否取消对称性?(y/n,默认n):" is_sym_off; is_sym_off=${is_sym_off:-n}
sed -i '/ISYM/d' INCAR
echo "ISYM = $( [ "$is_sym_off" = "y" ] && echo 0 || echo 2 )" >> INCAR
# 3. 截断能
read -p "是否增加截断能?(y/n,默认n):" is_encut; is_encut=${is_encut:-n}
sed -i '/ENCUT/d' INCAR
if [ "$is_encut" = "y" ]; then
while true; do
read -p "输入截断能(>400整数):" encut;
if [[ "$encut" =~ ^[0-9]+$ ]] && [ "$encut" -gt 400 ]; then break; fi
warning "输入无效!"
done
else
encut=400
fi
echo "ENCUT = $encut" >> INCAR
# 4. 优化精度
read -p "自定义优化精度?(y/n,默认n,格式:1E-08;-2E-02):" is_ediff; is_ediff=${is_ediff:-n}
sed -i '/EDIFF/d' INCAR; sed -i '/EDIFFG/d' INCAR
if [ "$is_ediff" = "y" ]; then
read -p "输入EDIFF;EDIFFG:" ediff_vals
ediff=$(echo $ediff_vals | cut -d';' -f1)
ediffg=$(echo $ediff_vals | cut -d';' -f2)
else
ediff=1E-05; ediffg=-2E-01
fi
echo "EDIFF = $ediff" >> INCAR; echo "EDIFFG = $ediffg" >> INCAR
# 5. NCORE/范德华修正(可选跳过)
read -p "添加NCORE?(y/n,默认n):" is_ncore; is_ncore=${is_ncore:-n}
[ "$is_ncore" = "y" ] && read -p "NCORE值:" ncore && sed -i '/NCORE/d' INCAR && echo "NCORE = $ncore" >> INCAR
read -p "添加范德华修正?(y/n,默认n):" is_vdw; is_vdw=${is_vdw:-n}
[ "$is_vdw" = "y" ] && read -p "IVDW值(1/2/10等):" ivdw && sed -i '/IVDW/d' INCAR && echo "IVDW = $ivdw" >> INCAR
# 6. 强制参数
sed -i '/ISTART/s/^/#/' INCAR; sed -i '/ICHARG/s/^/#/' INCAR
sed -i '/LWAVE/d' INCAR; sed -i '/LCHARG/d' INCAR
echo "LWAVE = .FALSE." >> INCAR; echo "LCHARG = .FALSE." >> INCAR
sed -i '/NSW/d' INCAR; sed -i '/IBRION/d' INCAR; sed -i '/ISIF/d' INCAR
echo "NSW = 100" >> INCAR; echo "IBRION = 2" >> INCAR; echo "ISIF = 3" >> INCAR
# ===================== 第三步:VASP运行命令 =====================
read -p "VASP运行命令(示例:mpirun -np 32 vasp_std,默认:mpirun -np 16 vasp_std):" vasp_cmd
vasp_cmd=${vasp_cmd:-"mpirun -np 16 vasp_std"}
log "✅ VASP命令:$vasp_cmd"
# ===================== 第四步:初始CONTCAR设置(核心:支持跳过常压优化) =====================
log "===== 初始结构设置 ====="
current_contcar=""
read -p "是否跳过常压(0GPa)优化?(y/n,默认n):" skip_0gpa; skip_0gpa=${skip_0gpa:-n}
if [ "$skip_0gpa" = "y" ]; then
# 跳过常压优化,询问已有CONTCAR路径
while true; do
read -p "请输入已有优化结果的CONTCAR文件路径(如:./CONTCAR.0GPa 或 ./P5GPa/CONTCAR.5GPa):" contcar_path
if check_non_empty_file "$contcar_path"; then
current_contcar="$contcar_path"
# 备份初始CONTCAR
cp "$current_contcar" "CONTCAR.initial"
current_contcar="CONTCAR.initial"
log "✅ 已选择已有CONTCAR作为初始输入:$contcar_path"
# 提取初始空间群
initial_space_group=$(get_space_group "$current_contcar")
log "✅ 初始空间群(基于已有CONTCAR):International: $initial_space_group"
break
else
warning "指定的CONTCAR文件不存在或为空,请重新输入!"
fi
done
else
# 执行常压(0GPa)优化
log "===== 常压(0GPa)结构优化 ====="
# 检查POSCAR(常压优化必须有)
if ! check_non_empty_file "POSCAR"; then
error "常压优化需要有效POSCAR文件!"
fi
# 提取初始空间群
initial_space_group=$(get_space_group "POSCAR")
log "✅ 初始空间群:International: $initial_space_group"
# 压力设置(0GPa)
sed -i '/PSTRESS/d' INCAR; echo "PSTRESS = 0" >> INCAR
optimization_done=false
max_attempts=5; attempt=0
while [ $attempt -lt $max_attempts ] && [ "$optimization_done" = false ]; do
attempt=$((attempt + 1))
log "第$attempt次常压优化..."
log_file="vasp_0GPa_$attempt.log"
if ! $vasp_cmd > "$log_file" 2>&1; then
warning "VASP运行失败,日志:$log_file"
read -p "重试?(y/n,默认n):" retry; retry=${retry:-n}
[ "$retry" = "n" ] && error "用户终止!"
continue
fi
# 检查CONTCAR是否有效(核心:不管收敛与否,优先用CONTCAR)
if check_non_empty_file "CONTCAR"; then
cp CONTCAR "CONTCAR.0GPa" # 备份0GPa的CONTCAR
current_contcar="CONTCAR.0GPa"
log "✅ 生成有效CONTCAR(0GPa),强制使用该文件作为后续输入"
optimization_done=true
else
warning "未生成有效CONTCAR,重试..."
continue
fi
# 可选:检查收敛条件(仅日志提示,不影响CONTCAR使用)
ionic_steps=$(grep -E '^ [0-9]+ F=' "$log_file" | wc -l)
reached=$(grep -c "reached required accuracy" "$log_file")
if [ "$ionic_steps" -lt 3 ] && [ "$reached" -ge 1 ]; then
log "✅ 常压优化收敛(离子步数:$ionic_steps)"
else
warning "常压优化未收敛,但仍使用CONTCAR作为后续输入"
fi
done
[ "$optimization_done" = false ] && error "常压优化未生成有效CONTCAR!"
fi
# ===================== 第五步:压力梯度设置(排序+校验) =====================
log "===== 压力梯度设置 ====="
echo "压力输入类型:"
echo "1) 特殊压力点(如:1 5 10 GPa)"
echo "2) 常压至最大值(如:0-80GPa,自动步长)"
echo "3) 分段压力(如:0-30,70-200GPa)"
read -p "选择类型(1/2/3,默认1):" p_type; p_type=${p_type:-1}
pressure_list=()
case $p_type in
1)
read -p "输入压力点(空格分隔):" p_points
pressure_list=($(echo "$p_points" | tr ' ' '\n' | sort -n | uniq))
;;
2)
read -p "压力最大值(GPa):" max_p
# 自动步长:0-10=1, 10-20=2, 20-50=5, 50+=10
for p in $(seq 0 1 10); do [ "$p" -le "$max_p" ] && pressure_list+=($p); done
for p in $(seq 12 2 20); do [ "$p" -le "$max_p" ] && pressure_list+=($p); done
for p in $(seq 25 5 50); do [ "$p" -le "$max_p" ] && pressure_list+=($p); done
p=60; while [ "$p" -le "$max_p" ]; do pressure_list+=($p); p=$((p+10)); done
pressure_list=($(echo "${pressure_list[@]}" | tr ' ' '\n' | sort -n | uniq))
;;
3)
read -p "分段压力(逗号分隔,如0-30,70-200):" p_seg
read -p "步长(auto/数字,默认auto):" step; step=${step:-auto}
IFS=',' read -ra segs <<< "$p_seg"
for seg in "${segs[@]}"; do
start=$(echo $seg | cut -d'-' -f1 | awk '{print int($1)}')
end=$(echo $seg | cut -d'-' -f2 | awk '{print int($1)}')
[ "$step" = "auto" ] && step=$( [ $end -le 10 ] && echo 1 || [ $end -le 20 ] && echo 2 || [ $end -le 50 ] && echo 5 || echo 10 )
for p in $(seq $start $step $end); do pressure_list+=($p); done
done
pressure_list=($(echo "${pressure_list[@]}" | tr ' ' '\n' | sort -n | uniq))
;;
esac
# 移除初始压力(如果跳过常压优化,初始压力可能不是0,需手动确认)
if [ "$skip_0gpa" = "n" ]; then
# 跳过常压优化时,移除0GPa(已计算)
pressure_list=($(echo "${pressure_list[@]}" | tr ' ' '\n' | grep -v '^0$' | sort -n))
fi
log "最终压力列表(从小到大):${pressure_list[*]} GPa"
# ===================== 第六步:能带/声子谱设置(原胞选项) =====================
log "===== 物性计算设置 ====="
# 能带计算(原胞选项)
read -p "是否计算能带?(y/n,默认n):" do_band; do_band=${do_band:-n}
band_incar=""
use_prim_cell=false
kpath_updated=false
if [ "$do_band" = "y" ]; then
read -p "指定能带INCAR?(y/n,默认n):" has_band_incar; has_band_incar=${has_band_incar:-n}
[ "$has_band_incar" = "y" ] && read -p "能带INCAR路径:" band_incar && [ ! -f "$band_incar" ] && error "能带INCAR不存在!"
# 询问是否用原胞计算能带
read -p "是否使用原胞进行能带计算?(y/n,默认n):" use_prim; use_prim=${use_prim:-n}
[ "$use_prim" = "y" ] && use_prim_cell=true && log "✅ 启用原胞进行能带计算"
# 生成并输出KPATH.in到终端
log "生成KPATH.in(vaspkit -task 303)"
# 临时使用初始CONTCAR生成KPATH.in
cp "$current_contcar" TMP_POSCAR
mv POSCAR POSCAR_BAK 2>/dev/null
mv TMP_POSCAR POSCAR
vaspkit -task 303
mv POSCAR_BAK POSCAR 2>/dev/null
rm -f TMP_POSCAR
log "当前KPATH.in内容:"
cat KPATH.in
read -p "确认KPATH.in是否合适?(y/n,默认y):" confirm_kpath; confirm_kpath=${confirm_kpath:-y}
[ "$confirm_kpath" = "n" ] && read -p "请输入自定义KPATH.in路径:" kpath_file && cp "$kpath_file" KPATH.in
fi
# 声子谱计算
read -p "是否计算声子谱?(y/n,默认n):" do_phono; do_phono=${do_phono:-n}
phono_incar=""
if [ "$do_phono" = "y" ]; then
check_command "phonopy"
read -p "指定声子INCAR?(y/n,默认n):" has_phono_incar; has_phono_incar=${has_phono_incar:-n}
[ "$has_phono_incar" = "y" ] && read -p "声子INCAR路径:" phono_incar && [ ! -f "$phono_incar" ] && error "声子INCAR不存在!"
fi
# ===================== 第七步:压力循环计算(核心:强制用CONTCAR) =====================
log "===== 开始压力循环计算 ====="
for p in "${pressure_list[@]}"; do
dir="P${p}GPa"
mkdir -p "$dir"
log "===== 处理压力点:$p GPa(文件夹:$dir) ====="
# 1. 复制初始/前一个压力点的CONTCAR(核心:强制用CONTCAR)
if ! check_non_empty_file "$current_contcar"; then
warning "初始/前一个CONTCAR($current_contcar)无效,请检查!"
read -p "是否终止计算?(y/n,默认y):" stop; stop=${stop:-y}
[ "$stop" = "y" ] && error "用户终止计算!" || continue
fi
cp "$current_contcar" "$dir/POSCAR" # 作为当前压力点的输入POSCAR
cp KPOINTS POTCAR INCAR "$dir/"
# 2. 修改当前压力的PSTRESS
p_kb=$(echo "$p * 10" | bc)
sed -i "s/PSTRESS = .*/PSTRESS = $p_kb/" "$dir/INCAR"
log "✅ 设置PSTRESS=$p_kb kB($p GPa)"
# 3. 进入文件夹优化结构
cd "$dir" || { warning "无法进入$dir,跳过"; continue; }
# 结构优化循环(强制用CONTCAR)
opt_done=false; attempt=0; max_attempts=3
while [ $attempt -lt $max_attempts ] && [ "$opt_done" = false ]; do
attempt=$((attempt + 1))
log "第$attempt次优化$p GPa结构..."
log_file="vasp_${p}GPa_$attempt.log"
if ! $vasp_cmd > "$log_file" 2>&1; then
warning "$p GPa第$attempt次VASP运行失败,日志:$log_file"
continue
fi
# 核心:检查CONTCAR是否有效(不管收敛与否)
if check_non_empty_file "CONTCAR"; then
cp CONTCAR "CONTCAR.${p}GPa" # 备份当前压力点的CONTCAR
current_contcar="../$dir/CONTCAR.${p}GPa" # 更新下一个压力点的输入
log "✅ $p GPa生成有效CONTCAR,强制使用该文件作为后续输入"
opt_done=true
# 可选:检查收敛条件(仅日志提示)
ionic_steps=$(grep -E '^ [0-9]+ F=' "$log_file" | wc -l)
reached=$(grep -c "reached required accuracy" "$log_file")
if [ "$ionic_steps" -lt 3 ] && [ "$reached" -ge 1 ]; then
log "✅ $p GPa优化收敛(离子步数:$ionic_steps)"
else
warning "$p GPa优化未收敛,但仍使用CONTCAR作为后续输入"
fi
# 检查空间群是否变化(仅能带计算时)
if [ "$do_band" = "y" ] && [ "$kpath_updated" = false ]; then
current_sg=$(get_space_group "CONTCAR")
if [ "$current_sg" != "$initial_space_group" ] && [ "$current_sg" != "UNKNOWN" ]; then
warning "空间群变化!初始:$initial_space_group → 当前:$current_sg"
read -p "是否更新KPATH.in?(y/n,默认n):" update_kpath; update_kpath=${update_kpath:-n}
if [ "$update_kpath" = "y" ]; then
# 基于当前CONTCAR生成新的KPATH.in
vaspkit -task 303
cp KPATH.in ../../KPATH.in
kpath_updated=true
log "✅ 已基于当前结构更新KPATH.in"
fi
fi
fi
else
warning "$p GPa第$attempt次优化未生成有效CONTCAR,重试..."
continue
fi
done
[ "$opt_done" = false ] && { warning "$p GPa优化失败,跳过"; cd ..; continue; }
# ===================== 能带计算(原胞选项) =====================
if [ "$do_band" = "y" ]; then
log "开始$p GPa能带计算..."
mkdir -p band
cd band || { warning "无法进入band,跳过"; cd ..; continue; }
# 复制当前压力点的CONTCAR到band目录
cp ../CONTCAR POSCAR
# 如果使用原胞,先生成PRIMCELL.vasp并替换POSCAR,再生成K点
if [ "$use_prim_cell" = true ]; then
log "生成原胞PRIMCELL.vasp(vaspkit -task 602)"
vaspkit -task 602
if check_non_empty_file "PRIMCELL.vasp"; then
mv POSCAR POSCAR_ori # 备份原结构
cp PRIMCELL.vasp POSCAR
log "✅ 已替换为原胞PRIMCELL.vasp作为能带计算输入"
# 重新生成K点(基于原胞)
log "基于原胞生成新的K点"
(echo 102; echo 2; echo 0.04) | vaspkit
else
warning "生成原胞失败,使用原CONTCAR继续"
fi
fi
# 复制其他文件
cp ../../POTCAR ../../INCAR .
# 处理能带INCAR
if [ -n "$band_incar" ]; then
cp "$band_incar" INCAR
else
sed -i '/NSW/s/^/#/' INCAR; sed -i '/IBRION/s/^/#/' INCAR
sed -i '/LWAVE/d' INCAR; sed -i '/LCHARG/d' INCAR
echo "LWAVE = .TRUE." >> INCAR; echo "LCHARG = .TRUE." >> INCAR
echo "LORBIT = 10" >> INCAR; echo "NEDOS = 5001" >> INCAR
fi
# 第一步SCF计算
log "执行第一步SCF自洽计算"
$vasp_cmd > band_calc1.log 2>&1
# 第二步能带计算(替换KPATH.in)
cp ../../KPATH.in KPOINTS
log "执行第二步能带计算"
$vasp_cmd > band_calc2.log 2>&1
# 数据处理
log "处理能带数据"
(echo 211; echo 1)|vaspkit
(echo 215; echo 1)|vaspkit
(echo 111; echo 2)|vaspkit
(echo 211; echo 2)|vaspkit
(echo 113; echo all;echo 2)|vaspkit
(echo 213; echo 2;echo all)|vaspkit
cd ..
fi
# ===================== 声子谱计算(强制用CONTCAR) =====================
if [ "$do_phono" = "y" ]; then
log "开始$p GPa声子谱计算..."
mkdir -p phono
cd phono || { warning "无法进入phono,跳过"; cd ..; continue; }
# 复制当前压力点的CONTCAR作为输入
cp ../CONTCAR POSCAR
cp ../../POTCAR ../../KPOINTS ../../INCAR .
# 处理声子INCAR
if [ -n "$phono_incar" ]; then
cp "$phono_incar" INCAR
else
sed -i '/NCORE/s/^/#/' INCAR
sed -i '/NSW/d' INCAR; sed -i '/IBRION/d' INCAR
echo "NSW = 1" >> INCAR
grep -q "IVDW" INCAR && echo "IBRION = 6" >> INCAR || echo "IBRION = 8" >> INCAR
fi
# 运行VASP+phonopy
log "执行声子谱VASP计算"
$vasp_cmd > phono_vasp.log 2>&1
if check_non_empty_file "vasprun.xml"; then
# 生成KPATH.phonopy
cat > KPATH.phonopy << EOF
NPOINTS = 501
DIM = 1 1 1
BAND = AUTO
BAND_LABELS = AUTO
TETRAHEDRON = .TRUE.
PDOS = AUTO
BAND_CONNECTION = .TRUE.
FORCE_CONSTANTS = READ
EOF
# 运行phonopy
log "执行phonopy计算"
phonopy --fc vasprun.xml
phonopy -s -p KPATH.phonopy --pa=auto
phonopy-bandplot --gnuplot | tee phono.txt
rm -f *.yaml
log "✅ 声子谱计算完成"
else
warning "未生成有效vasprun.xml,跳过phonopy计算"
fi
cd ..
fi
cd .. # 返回主目录
done
# ===================== 计算完成 =====================
log "${GREEN}===== 所有计算完成! =====${NC}"
log "✅ 初始CONTCAR:$current_contcar(跳过常压优化)/ CONTCAR.0GPa(常压优化)"
log "✅ 压力点CONTCAR:P*GPa/CONTCAR.*GPa(每个压力点的核心输出)"
log "✅ 关键文件:"
log " - 能带计算:P*GPa/band/(使用CONTCAR/原胞PRIMCELL.vasp作为输入)"
log " - 声子谱计算:P*GPa/phono/(使用CONTCAR作为输入)"
log "✅ 注意:所有后续计算均强制使用CONTCAR(无论是否收敛)"