CentOS+Intel+OpenMPI+FFTW编译VASP 5.4.1教程

发布时间:2026/10/23 21:26:45
CentOS+Intel+OpenMPI+FFTW编译VASP 5.4.1教程

这篇教程解决一个很实在的问题:很多玩材料计算的同学,拿到VASP 5.4.1源码包之后,卡在编译环境上,网上的资料零零散散,要么只讲GCC,要么直接让你用Intel MPI,很少有人把CentOS + Intel编译器 + OpenMPI + FFTW这条完整链路讲透。这篇不聊物理和算法,只聊怎么把VASP 5.4.1在CentOS上编译出一个能稳定并行跑起来的可执行文件。适合刚开始接触第一性原理计算、或者需要自己维护计算服务器的新手参考,也适合被makefile折腾到想摔键盘的老玩家快速查错。

1. 整体思路:为什么是Intel编译器 + OpenMPI + FFTW这套组合

1.1 为什么优先选择Intel编译器

VASP的核心代码是Fortran写的,而且极度依赖计算性能。同一台机器,用GCC和Intel编译器编译出来的VASP,跑同一个小体系,最终单步耗时能差出百分之二三十,这在高通量计算里是不可忽略的成本。Intel编译器对x86平台的内存布局、向量化指令调度、循环展开做过多轮针对性优化,尤其配合Intel MKL数学库,能把BLAS、LAPACK、ScaLAPACK这些基础线性代数操作压到很低的延迟。

另外一个现实原因是,VASP 5.4.1这个版本发布年代较早,它编译时对编译器行为很敏感,Intel的ifort在Fortran标准支持和ABI兼容性上更稳。VASP官方也一直把Intel编译器作为主要支持对象。所以只要不是非要追求GCC全家桶,用Intel编译器是最少踩坑的路。

1.2 为什么还要再单独编译一个OpenMPI

很多教程一上来就推荐Intel MPI,因为MKL里默认的BLACS库可以和Intel MPI无缝配合,少调一个OpenMPI编译参数。但问题是,不少课题组现有的管理系统、作业调度脚本、其他第三方软件都是基于OpenMPI部署的,如果VASP单独用Intel MPI,那环境就割裂了,后面做跨软件联调很痛苦。OpenMPI开箱即用,社区活跃,问题排查资料也多。

所以这套方案的核心设计就是:用Intel编译器去编译OpenMPI,再用OpenMPI的mpifort包装器去编译VASP,最后链接MKL数学库和独立的FFTW库。关键点在于“用Intel编译器编译OpenMPI”这一步,很多教程忽略了它,直接拿系统自带的OpenMPI顶上去,结果VASP编译时Fortran模块ABI对不上,编译出来也能跑,但容易在运行中途出现莫名奇妙的SIGSEGV。

1.3 整条编译链路

依赖顺序大概是这样:系统基础环境 → Intel oneAPI编译器 → OpenMPI → FFTW → VASP。先装编译器,再编译OpenMPI,最后编VASP。这个顺序不能乱。如果先编译OpenMPI、后装Intel编译器,OpenMPI里的fortran wrapper可能没有正确绑定到ifort,后面VASP编译时调用mpifort却连上gfortran,编译错误五花八门,查起来非常头痛。

2. 环境准备:从裸CentOS到编译条件就绪

2.1 CentOS系统基础依赖

我用的是CentOS 7.9作为基准环境,CentOS 8/9的流程也差不多。首先确保一些基础工具已经装好:

sudo yum update -y sudo yum install -y gcc gcc-c++ make perl wget tar gzip

这里gcc不是给VASP用,而是OpenMPI在configure阶段需要C编译器做检测,以及后续编译一些辅助工具时会用到。还需要libevent和hwloc,这是OpenMPI运行时的底层依赖:

sudo yum install -y libevent-devel hwloc-devel

另外,把堆栈限制打开,VASP跑基于MPI的并行任务时,默认8MB的stack经常不够用:

ulimit -s unlimited

这个设置最好写入/etc/security/limits.conf或者当前用户的~/.bashrc里,否则每次重启终端都要重新设。

2.2 安装Intel oneAPI编译器与MKL

Intel现在已经把编译器套件整合到oneAPI里了,基础工具链可以直接从官网下载。需要安装Base Toolkit和HPC Toolkit,里面包含ifort、icpc、MKL。下载完安装脚本后,用命令行方式装:

sudo sh ./l_BaseKit_p_*.sh -a --silent --eula accept sudo sh ./l_HPCKit_p_*.sh -a --silent --eula accept

装完之后,环境变量默认在/opt/intel/oneapi/setvars.sh。每次编译前都要加载:

source /opt/intel/oneapi/setvars.sh intel64

然后验证:

which ifort which mklvars.sh

看到路径就说明环境生效了。有一点要提醒,比较新的oneAPI版本里,Intel已经把主推方向转移到ifx上,ifort作为兼容包还会保留一段时间,但VASP 5.4.1这个老代码对ifx的支持并不友好,建议用ifort。如果发现自己的oneAPI里没有ifort,可以直接用Intel Parallel Studio XE 2020 Update 3左右的版本,它自带成熟的ifort,和VASP 5.4.1磨合得比较好。

2.3 用ifort编译OpenMPI

这里是我踩过最多坑的一步。OpenMPI的版本不是越新越好,VASP 5.4.1年代老,不建议选5.x以上。经过反复测试,OpenMPI 3.1.x系列是稳妥选择,4.0.x也能用,但5.x系列因为PMIx接口和运行时的变化,容易出现编译通过但运行启动就挂的情况。

下载好OpenMPI 3.1.6源码包后,解压并配置:

tar -xzf openmpi-3.1.6.tar.gz cd openmpi-3.1.6 ./configure --prefix=/opt/openmpi \ CC=icc CXX=icpc \ F77=ifort FC=ifort \ --enable-mpi-fortran=both \ --disable-cuda

这里重点解释几个参数:

  • CC=icc CXX=icpc F77=ifort FC=ifort:让OpenMPI的编译器和包装器都绑定到Intel工具链上,这样后面mpifort调用时默认就是ifort。
  • --enable-mpi-fortran=both:同时生成Fortran 77和Fortran 90模块接口,VASP大量使用Fortran 90,如果没有这个选项,后续会报找不到mpi.mod。
  • --disable-cuda:普通CPU版本不需要CUDA支持,可以避免依赖检测带来的麻烦。

配置完成后编译安装:

make -j8 sudo make install

安装完成后,编辑/etc/profile.d/openmpi.sh,把OpenMPI加入PATH和LD_LIBRARY_PATH:

export PATH=/opt/openmpi/bin:$PATH export LD_LIBRARY_PATH=/opt/openmpi/lib:$LD_LIBRARY_PATH export MANPATH=/opt/openmpi/share/man:$MANPATH

重开终端后,用which mpifort确认存在,再执行:

mpifort -show

看到输出里出现了ifort而不是gfortran,就说明包装器绑定正确。这一步是整个编译流程里最重要的体检指标。

2.4 编译FFTW 3.3.8

VASP在进行平面波变换时需要FFT库,我们可以用MKL自带的FFTW3兼容接口,但既然标题要求了FFTW环境,那我们就用独立的FFTW库。独立FFTW的好处是路径明确、版本可控,后面排查问题更直接。

下载FFTW 3.3.8源码:

tar -xzf fftw-3.3.8.tar.gz cd fftw-3.3.8 ./configure --prefix=/opt/fftw \ CC=icc CFLAGS="-O3 -xHost" \ --enable-sse2 --enable-avx

--enable-sse2和--enable-avx是让FFTW在x86平台上自动选择向量化指令集,虽然VASP的核心计算不算FFTW瓶颈,但这部分优化也能带来几个百分点的提升。然后:

make -j8 sudo make install

编译后确认/opt/fftw/lib/libfftw3.a或libfftw3.so存在即可。需要注意,VASP 5.4.1只需要双精度FFTW的默认版本就够了,不用额外编译--enable-float,除非你自己有特殊需求。

3. VASP 5.4.1核心配置:makefile.include拆解

3.1 makefile.include机制说明

VASP从5.x开始就不是标准的自动工具构建,而是通过源码目录里的makefile配合makefile.include来完成配置。makefile.include本质上是一个片段,里面定义编译器、预处理器、优化选项、库路径和链接库,make的时候会把它include进主makefile。

在VASP 5.4.1源码包里,一般有一个makefile.include模板或者arch目录下带不同平台的示例。我们要做的是先备份默认文件,再改成适合当前环境的配置。

cd vasp.5.4.1 cp makefile.include makefile.include.bak

3.2 核心配置项逐行解读

下面这个配置,对应Intel oneAPI + OpenMPI 3.1.x + 独立FFTW的环境,可以直接作为蓝本使用:

# 预处理器 CPP = gcc -E -P -C -w CPP_OPTIONS = -DHOST=\"LinuxIFC\" -DMPI -DMPI_OPT \ -Duse_collective -DscaLAPACK \ -DCACHE_SIZE=4000 -Davoidalloc # Fortran编译器 FC = mpifort FCL = mpifort # 编译选项 FREE = -free FFLAGS = -assume byterecl -w -xHost -O2 $(FREE) OFLAG = -O2 OFLAG_IN = -O2 # MKL数学库 BLAS = -L$(MKLROOT)/lib/intel64 -lmkl_intel_lp64 \ -lmkl_sequential -lmkl_core -lpthread LAPACK = -L$(MKLROOT)/lib/intel64 -lmkl_intel_lp64 \ -lmkl_sequential -lmkl_core -lpthread SCA = -L$(MKLROOT)/lib/intel64 -lmkl_scalapack_lp64 \ -lmkl_blacs_openmpi_lp64 -lmkl_intel_lp64 \ -lmkl_sequential -lmkl_core -lpthread # FFTW FFTW = -L/opt/fftw/lib -lfftw3 # 最终链接库顺序 LLIBS = $(SCA) $(LAPACK) $(BLAS) $(FFTW)

这里有几个关键的“为什么”必须说清楚:

  • FC = mpifort:不是直接用ifort,而是通过OpenMPI的包装器调用ifort,这样VASP编译时能自动找到MPI的Fortran模块和库。
  • -lmkl_sequential:MKL内部不启用OpenMP线程模式,而是用纯串行版本。因为VASP的MPI并行模式如果和MKL的OpenMP线程混在一起,核多后容易出现线程过度订阅,性能不升反降。
  • -lmkl_blacs_openmpi_lp64:这是ScaLAPACK与MPI实现对接的BLACS库。如果用的是Intel MPI,应该写-lmkl_blacs_intelmpi_lp64;我们这里用OpenMPI,所以必须写成_openmpi_,写错的结果是链接阶段能过,但运行到K点并行时会崩溃。
  • -DCACHE_SIZE=4000:这是CPU缓存大小设置,单位是KB。大部分现代计算节点L3缓存都在16MB甚至更高,这里写4000是为老一代Xeon优化,实际可以根据机器调整,例如-DCACHE_SIZE=20480。
  • -Duse_collective:让MPI_Allreduce等操作使用集合通信优化版本。这个宏在不同机器上表现不太稳定,如果编译完运行后速度反而变慢,可以去掉再重编对比。

3.3 实际编译与生成可执行文件

配置写好之后,进入源码目录,编译:

source /opt/intel/oneapi/setvars.sh intel64 export PATH=/opt/openmpi/bin:$PATH export LD_LIBRARY_PATH=/opt/openmpi/lib:/opt/fftw/lib:$LD_LIBRARY_PATH make clean make -j8

如果前面环境变量和配置没问题,编译过程会顺利走完,最终生成一个vasp可执行文件。这个过程第一次会比较慢,大概5到15分钟,取决于机器核数和磁盘速度。

编译完成可以快速验证一下:

./vasp

如果没有参数,VASP会打印一段说明后退出,显示类似“VASP 5.4.1”的版本号,这就说明基本编译成功了。

4. 常见问题与排查技巧实录

4.1 mpifort包装器仍然指向gfortran

如果mpifort -show的输出里看到gfortran,说明OpenMPI编译时没有正确绑定ifort。最常见的根源是configure阶段没有写F77=ifort FC=ifort,或者当时的环境变量没有加载oneAPI。

解决办法也不复杂,重新编译OpenMPI,在configure前先:

source /opt/intel/oneapi/setvars.sh intel64

然后重新执行configure和make install。如果不想重编,也可以手动修改mpifort这个脚本,找到F90和F77变量改成ifort,但我不推荐这么做,容易埋雷。

4.2 make时报错找不到mpi模块

错误类似:

ifort: catastrophic error: cannot open module file 'mpi.mod'

这个报错说明FC没有真正调用mpifort,或者mpifort使用的编译器不对。先检查makefile.include里有没有被注释掉“FC”,再看mpifort -show的输出。如果输出正确还报这个错,大概率是OpenMPI没有编译Fortran 90模块接口,回到2.3节的--enable-mpi-fortran=both重新编译OpenMPI。

4.3 FFTW链接时报undefined reference

链接VASP时出现:

undefined reference to fftw_execute

第一个原因是链接顺序错误。GNU ld对静态库是单遍扫描的,-lfftw3必须放在所有需要FFTW符号的库之后。在上面的LLIBS = $(SCA) $(LAPACK) $(BLAS) $(FFTW)里,FFTW放在最后,这个顺序是很多教程容易忽略的细节。

第二个原因是FFTW库版本不对。检查是不是编译成了单精度版本,如果源码包在configure时加了--enable-float,那库名会变成libfftw3f.a,VASP默认链接的是fftw3。所以编译FFTW时不要乱加float选项。

4.4 运行VASP时启动崩溃或CPU占用瞬间下降

编译通过但mpirun -np 8 ./vasp一执行就挂掉,或者刚跑起来没多久进程全退。先看有没有提示OpenMPI版本相关的“PMIx”错误。如果有,直接确认OpenMPI版本,VASP 5.4.1建议用3.1.x,不要用5.x。

如果不是版本问题,就检查环境变量:

export LD_LIBRARY_PATH=/opt/openmpi/lib:/opt/fftw/lib:$LD_LIBRARY_PATH export OMP_NUM_THREADS=1

OMP_NUM_THREADS=1非常关键。很多OpenMPI构建会带动OpenMP运行时,如果不限制线程数,每个MPI进程会再去开一堆线程,白白吃满内存。

4.5 常见问题速查表

现象大概率原因处理方向
make时找不到mpifortPATH没加OpenMPI路径export PATH=/opt/openmpi/bin:$PATH
编译时默认连上gfortranOpenMPI未绑定ifort重新用ifort编译OpenMPI
链接fftw相关报错库顺序或FFTW版本把-lfftw3放最后,去掉float选项
运行启动即崩OpenMPI版本过新降到OpenMPI 3.1.x
大体系跑得慢且内存爆炸MKL内部线程过度订阅OMP_NUM_THREADS=1
并行结果有时对不上浮点非确定性FFLAGS中不要加-ffast-math类激进选项

5. 性能验证与并行参数优化

5.1 用一个标准算例快速验证

编译成功后,最好先用一个已知收敛时间的小体系做对比测试,而不是直接丢上生产任务。我自己习惯准备一个4原子或者8原子的块体结构,用单一Gamma点做几步电子自洽,分别用4核、8核、16核跑一遍,对比OUTCAR里的耗时。

查看时间的方法:

grep "LOOP:" OUTCAR | tail -5

输出里的每一行对应电子自洽迭代步,最后一列就是该步耗时。对比不同进程数的耗时,就能看出并行扩展性是否正常。如果8核比4核还慢,基本就是线程绑定或者MKL线程库设置出了问题。

5.2 进程绑定与运行参数

运行VASP时,裸的mpirun -np 8 vasp虽然也能跑,但进程在节点间和核心间乱跳,会导致缓存命中率下降。现代OpenMPI支持核心绑定:

mpirun --bind-to core --map-by core -np 8 vasp

这会让每个进程绑定到一个物理核上。注意这里不要在命令行里额外写--oversubscribe,那会允许进程数超过核心数,反而降低效率。

同时检查一下是不是超线程在干扰性能。一般来说,用物理核数作为进程数比较稳妥,比如单节点16个物理核就用-np 16,不要直接-np 32,超线程对VASP这类计算密集型任务帮助有限,甚至带来负优化。

5.3 是否启用OpenMP并行

VASP 5.4.1本身支持-Dopenmp的OpenMP模式,但和MPI混用需要非常小心,尤其是配合OpenMPI + MKL时,线程层级过多反而难调试。我的经验是:除非你是跑特别大的单K点体系,并且已经仔细测过各种线程数组合的收益,否则建议先用纯MPI模式,也就是本教程的配置,稳定第一。等把这套环境跑熟之后,再考虑要不要开-Dopenmp玩OMP+MPI混合并行。

5.4 多节点并行时的环境注意事项

如果要跨节点跑,需要确保所有计算节点上的OpenMPI和VASP路径一致。最简单的方式是把OpenMPI、FFTW、VASP都装到所有节点的相同路径下,然后通过调度系统去启动任务。另外LD_LIBRARY_PATH需要在作业脚本里显式设置,不要依赖登录节点的.bashrc,作业脚本里写清楚:

source /opt/intel/oneapi/setvars.sh intel64 export PATH=/opt/openmpi/bin:$PATH export LD_LIBRARY_PATH=/opt/openmpi/lib:/opt/fftw/lib:$LD_LIBRARY_PATH export OMP_NUM_THREADS=1 mpirun --bind-to core -np 32 vasp

跨节点时还可以加上--mca btl_tcp_if_include来指定高速网络接口,但不同集群的网络设备差异很大,需要根据实际环境调整。

最后再分享一个我自己的小习惯:每次编译完VASP,别急着删源码目录,把makefile.include、环境变量设置和编译日志都留档,放在一个build_log文件夹里。之后Unity版本升级、换机器、加节点,照着这个记录重新编译,能省下大量排错时间。这套环境我已经在多个CentOS机器上复现过,核心就是OpenMPI绑定ifort、MKL选择sequential模式、库链接顺序这三件事,只要这三件不出错,VASP 5.4.1的编译基本一次就能过。