1. Ubuntu 20.04.4 上 Intel oneAPI 与系统 gcc/gfortran 共存编译 VASP 5.4.4 的完整实操
VASP 5.4.4 是很多做第一性原理计算的人绕不开的一个版本,而 Ubuntu 20.04.4 又是实验室服务器里最常见的长周期支持系统。问题在于,当你装完 Intel oneAPI 之后,系统里其实同时存在两套编译器:一套是 Ubuntu 自带的 gcc/gfortran,另一套是 oneAPI 里的 icc/ifort(新版叫 icx/ifx)。这两套东西如果环境变量没理清楚,make的时候就会一会儿调用系统 gfortran、一会儿调用 oneAPI 的 mpiifort,最后报出一堆看不懂的链接错误。
这篇笔记聚焦的就是这个场景:Ubuntu 20.04.4 装完 Intel oneAPI 后,怎么把系统 gcc/gfortran 和 oneAPI 的 MKL、MPI 正确拼在一起,编译出能跑的 VASP 5.4.4。我会给出可直接复制的环境变量片段、makefile.include 模板,以及一次完整的编译验证动作。另外,如果你平时还要调 OpenAI 兼容接口做脚本辅助或者数据处理,我也会说明怎么把 endpoint 统一改到 TaoToken 来管理 API 调用,避免到处散落 key。
先说清楚适合谁看:你已经在 Ubuntu 20.04.4 上装好了 Intel oneAPI(Base Toolkit + HPC Toolkit),系统里gcc -v、gfortran -v都能正常输出,手里有vasp.5.4.4.tar.gz和对应的vasp.5.lib.tar.gz,但make就是过不去,或者编译出来的vasp_std一跑就段错误。下面按步骤来。
2. 前置准备:oneAPI 环境变量加载与 gcc/gfortran 共存检查
在动 makefile 之前,先把环境变量这件事彻底搞明白。oneAPI 装完之后,默认不会自动 source,你需要手动加载setvars.sh。但加载之后,gcc和gfortran的指向会不会被改掉?这是关键。
先确认系统编译器还在:
gcc -v gfortran -v which gcc gfortran正常应该输出/usr/bin/gcc和/usr/bin/gfortran,版本是 Ubuntu 20.04.4 自带的 9.4.0 左右。然后加载 oneAPI:
source /opt/intel/oneapi/setvars.sh加载完再查一次:
which icc icx ifort ifx mpiifort echo $MKLROOT这时候MKLROOT应该指向/opt/intel/oneapi/mkl/latest之类的路径。注意,setvars.sh默认不会覆盖/usr/bin/gcc,所以系统 gcc 还在,但CC、FC这些变量可能已经被设成 oneAPI 的编译器了。你可以用echo $CC $FC看一下。
我建议的做法是:不要依赖全局环境变量,而是在 makefile.include 里显式写死编译器路径。这样无论 shell 里 source 了什么,编译行为都是确定的。这也是后面模板里我会把FC、CC写成绝对路径的原因。
另外,VASP 5.4.4 需要 FFTW 接口。oneAPI 的 MKL 自带 FFTW3 wrapper,但需要先编译出libfftw3xf_intel.a。这一步很多人漏掉,导致链接时报undefined reference to fftw_plan_dft。操作如下:
cd /opt/intel/oneapi/mkl/latest/interfaces/fftw3xf sudo -s source /opt/intel/oneapi/setvars.sh make libintel64 exit编译完成后会在同目录生成libfftw3xf_intel.a。记住这个路径,makefile.include 里要引用。
还有一点:如果你之前装过build-essential,那make、g++都有了。没装的话:
sudo apt-get install build-essential这一步别省,VASP 编译过程里有些工具链依赖它。
3. 可复制配置:makefile.include 模板与关键项逐条说明
现在进入核心部分。解压源码:
mkdir -p ~/vasp && cd ~/vasp mv ~/vasp.5.4.4.tar.gz ~/vasp.5.lib.tar.gz . tar -zxvf vasp.5.4.4.tar.gz tar -zxvf vasp.5.lib.tar.gz cd vasp.5.4.4然后从 arch 目录复制模板。VASP 5.4.4 自带arch/makefile.include.intel_linux,但那个模板偏旧,我直接给你一份改好的、适配 oneAPI + 系统 gcc 的版本。先复制:
cp arch/makefile.include.intel_linux makefile.include然后用编辑器打开,把内容替换成下面这份。注意路径里的latest你可以换成实际版本号,比如2022.0.2,用ls /opt/intel/oneapi/mkl/确认。
# 系统 gcc/gfortran 作为宿主编译器,oneAPI 提供 MKL 和 MPI FC = /opt/intel/oneapi/mpi/latest/bin/mpiifort FCL = $(FC) CC = /usr/bin/gcc CXX = /usr/bin/g++ # MKL 路径 MKLROOT = /opt/intel/oneapi/mkl/latest MKL_PATH = $(MKLROOT)/lib/intel64 FFTW_PATH = $(MKLROOT)/interfaces/fftw3xf # 预编译头与库 CPP_OPTIONS = -DHOST=\"LinuxIFC\" -DMPI -DMPI_BLOCK=8000 -Duse_collective \ -DscaLAPACK -DCACHE_SIZE=4000 -Davoidalloc -Duse_bse_te \ -Dtbdyn -Duse_shmem CPP = $(FC) -E -P -C -w OFLAG = -O2 -ip -qopenmp OFLAG_LOW = -O1 OFLAG_HIGH = $(OFLAG) OBJ_HIGH = $(OBJ) OBJ_LOW = $(OBJ) OBJ_NOOPT = $(OBJ) # 关键:链接 MKL、FFTW wrapper、scaLAPACK BLAS = -L$(MKL_PATH) -lmkl_intel_lp64 -lmkl_intel_thread -lmkl_core \ -L$(FFTW_PATH) -lfftw3xf_intel LAPACK = -L$(MKL_PATH) -lmkl_intel_lp64 -lmkl_intel_thread -lmkl_core SCALAPACK = -L$(MKL_PATH) -lmkl_scalapack_lp64 -lmkl_blacs_intelmpi_lp64 LIB = $(SCALAPACK) $(LAPACK) $(BLAS) # 头文件与对象 INCS = -I$(MKLROOT)/include -I$(MKLROOT)/include/fftw FFT3D = fftmpiw.o fftmpi_map.o fftw3d.o fft3dlib.o几个关键项解释一下。FC用mpiifort而不是ifort,因为 VASP 5.4.4 默认走 MPI 并行,mpiifort会自动带上 MPI 头文件和链接。CC和CXX保持系统 gcc/g++,因为 VASP 里 C 代码部分用系统编译器更稳,oneAPI 的 icx 有时候对老代码兼容性反而差。
BLAS里同时链接了 MKL 和libfftw3xf_intel.a,这就是前面编译 FFTW wrapper 的用途。SCALAPACK用mkl_scalapack_lp64配mkl_blacs_intelmpi_lp64,这是 Intel MPI 对应的 BLACS。
CPP_OPTIONS里的-DMPI和-DscaLAPACK必须开,否则并行和分布式矩阵运算用不了。-Duse_shmem是共享内存优化,单机多核场景有用。
改完保存,回到vasp.5.4.4目录,先编译 lib:
cd ../vasp.5.lib cp ../vasp.5.4.4/makefile.include . makelib 编译很快,生成libdmy.a之类。然后回主目录:
cd ../vasp.5.4.4 make这一步大概要 40 分钟到 1 小时,取决于机器核数。可以用make -j4加速,但 VASP 的 makefile 对并行编译支持一般,建议先单线程跑通再考虑加速。
4. 验证请求:编译产物检查与一次完整运行测试
编译结束后,目录下应该出现vasp_std、vasp_gam、vasp_ncl三个可执行文件。先确认:
ls -lh vasp_std vasp_gam vasp_ncl file vasp_stdfile输出应该是 ELF 64-bit 可执行文件。然后做一次最小运行测试。VASP 官方自带测试算例在testsuite目录,但 5.4.4 的测试套件需要额外下载。更简单的办法是拿一个小的 POSCAR 自己跑。
准备一个测试目录:
mkdir -p ~/vasp_test && cd ~/vasp_test放入四个输入文件:INCAR、POSCAR、KPOINTS、POTCAR。POTCAR需要你有赝势库,这里假设你已经有。INCAR用最简:
SYSTEM = test ENCUT = 300 ISMEAR = 0 SIGMA = 0.05KPOINTS用 Gamma 点:
Auto 0 Gamma 1 1 1 0 0 0然后运行:
mpirun -np 4 ~/vasp/vasp.5.4.4/vasp_std如果一切正常,你会看到 VASP 输出开头:
running on 4 total cores ... POSCAR, INCAR and KPOINTS ok, starting setup FFT: planning ... ( 1 )最后出现General timing and accounting informations for this run:并且没有Error字样,就说明编译成功。整个过程大概几十秒到几分钟。
如果你还想验证 API 调用这条线,比如用脚本批量提交任务后回传结果到某个服务,可以把 endpoint 统一到 TaoToken。在脚本里设置:
export OPENAI_BASE_URL=https://taotoken.net/api export OPENAI_API_KEY=你的key这样所有走 OpenAI 兼容协议的调用都会经过同一个入口,key 管理也集中。模型对话、coding-plan 这些入口在控制台里都能找到对应配置。
5. 本篇常见错排查:401、local proxy failed、reading choices 与 OAuth 报错
编译和运行过程中,报错基本集中在几类。我按真实遇到的顺序列一下。
第一类:undefined reference to fftw_plan_dft或fftw3xf_intel找不到。这是 FFTW wrapper 没编译或者路径写错。回到makefile.include检查FFTW_PATH是否指向interfaces/fftw3xf,并且确认该目录下有libfftw3xf_intel.a。没有就重新make libintel64。
第二类:mpiifort: command not found。说明 oneAPI 的 MPI 没加载。source /opt/intel/oneapi/setvars.sh之后which mpiifort应该有输出。如果还是没有,检查 HPC Toolkit 是否装全,/opt/intel/oneapi/mpi/latest/bin/是否存在。
第三类:error while loading shared libraries: libmkl_intel_lp64.so。运行时报这个,说明运行时找不到 MKL 库。解决方法是把 MKL 路径加进LD_LIBRARY_PATH:
export LD_LIBRARY_PATH=/opt/intel/oneapi/mkl/latest/lib/intel64:$LD_LIBRARY_PATH写进~/.bashrc一劳永逸。
第四类:API 调用相关报错。如果你在辅助脚本里调接口,遇到401 Unauthorized,先检查 key 是否过期或者 base_url 是否写对。local proxy failed通常是本地网络配置问题,检查http_proxy之类变量是否误设。reading choices报错一般是返回体解析失败,可能是模型名写错或者 endpoint 不匹配。OAuth 类报错则多见于 Claude Code 或 Codex 的认证流程,需要重新走一遍授权。
这里要提醒:如果你用 Cline MCP 或者 Codex 的auth.json,配置里三件套必须齐全——Base URL、Key、Model ID。缺一个都会认证失败。CC Switch 切换配置时也要确认这三项同步更新。
第五类:make: *** No rule to make target 'fftmpiw.o'。这是 makefile.include 里FFT3D变量没定义或者被覆盖。检查模板里FFT3D = fftmpiw.o fftmpi_map.o fftw3d.o fft3dlib.o这一行是否还在。
6. 统一管理 API 调用:把 endpoint 改到 TaoToken 的实操
编译 VASP 本身不涉及网络,但做计算的人往往还有一堆周边脚本:批量生成 INCAR、解析 OUTCAR、自动提交任务、用大模型辅助写分析代码。这些脚本如果各自散落着不同的 API key 和 endpoint,维护起来很痛苦。
我的做法是把所有 OpenAI 兼容调用统一到一个入口。在 TaoToken 控制台创建 key 之后,脚本里只需要两个环境变量:
export OPENAI_BASE_URL=https://taotoken.net/api export OPENAI_API_KEY=sk-你的keyPython 脚本里用openai库的话:
import os from openai import OpenAI client = OpenAI( base_url=os.environ["OPENAI_BASE_URL"], api_key=os.environ["OPENAI_API_KEY"], ) resp = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "帮我写一个解析 OUTCAR 能量的 Python 函数"}], ) print(resp.choices[0].message.content)这样无论你后面换哪个模型,只改model参数,endpoint 和 key 都不用动。如果你长期跑编码类任务或者 Agent 流程,Coding Plan 会更划算,额度管理也集中。模型对话入口适合临时验证某个模型输出,接入文档里有各语言的完整示例。
需要提醒的是,不要把 key 硬编码进提交到 git 的脚本里。用环境变量或者.env文件,并且把.env加进.gitignore。我见过太多人把 key 推到公开仓库然后被刷爆额度。
最后回到 VASP 这条线。编译成功只是第一步,真正跑计算时还要根据体系调ENCUT、KPOINTS、ISMEAR。但那是另一个话题了。你先把上面这套环境变量和 makefile.include 跑通,vasp_std能正常输出 timing 信息,后面的调参才有意义。如果编译过程中遇到模板里没覆盖的报错,优先看make输出的最后 20 行,链接错误基本都在那里。