LAMMPS自定义命令插件实操
从源码编译ys_report插件,实际完成1/2 MPI进程的加载、clear、卸载和重载。
阅读本篇目录
需要增加自己的输入命令时,可以使用LAMMPS的动态插件接口。本篇实际编译一个ys_report命令,它通过公开C接口读取全局原子数并写入本地JSON,然后分别用1个和2个MPI进程完成加载、清空模型、卸载和重载。
下载插件源码、版本匹配的API头文件、构建脚本与实际日志,解压进入run.sh目录。包内提供源码,不分发预编译so;LAMMPS及其模块由集群现有环境提供。
1 提交编译与运行#
sbatch submit.slurm
模板申请核时P100分区2个CPU核和1张GPU资源;这次使用该构建中的普通CPU/MPI接口,不启用GPU求力。套餐用户用yskit生成所属分区脚本,保留两个CPU核,在已分配资源中执行bash run.sh。
run.sh先在本目录build下编译插件,再分别运行one-rank和two-rank,最后检查状态。已有work或build请重新解压,避免混用不同版本的二进制。编译器及MPI要与目标LAMMPS一致:本例LAMMPS30Sep2026、GNU C++13.3.0/C++17、Open MPI5.0.10,1个OpenMP线程。
2 插件完整源码#
// Yuansuan HPC tutorial: source-only command plugin for LAMMPS 30 Sep 2026.
// SPDX-License-Identifier: GPL-2.0-only
#include "lammpsplugin.h"
#include "version.h"
#include "command.h"
#include "library.h"
#include <mpi.h>
#include <fstream>
#include <stdexcept>
namespace LAMMPS_NS {
class YsStateReport : public Command {
public:
explicit YsStateReport(LAMMPS *instance) : Command(instance) {}
void command(int argc, char **argv) override {
if (argc != 1) throw std::invalid_argument("ys_report needs one output filename");
int rank = -1;
MPI_Comm_rank(world, &rank);
if (rank == 0) {
std::ofstream output(argv[0]);
if (!output) throw std::runtime_error("cannot create ys_report output");
output << "{\"atoms\":" << static_cast<long long>(lammps_get_natoms(lmp)) << ",\"plugin\":\"ys_report\"}\n";
}
}
};
}
static void *construct_report(void *instance) {
return new LAMMPS_NS::YsStateReport(static_cast<LAMMPS_NS::LAMMPS *>(instance));
}
extern "C" void lammpsplugin_init(void *instance, void *library, void *registration) {
lammpsplugin_t description{};
description.version = LAMMPS_VERSION;
description.style = "command";
description.name = "ys_report";
description.info = "Write the current global atom count to a local JSON file";
description.author = "Yuansuan Technology";
description.creator.v1 = &construct_report;
description.handle = library;
reinterpret_cast<lammpsplugin_regfunc>(registration)(&description, instance);
}
这个示例注册一个新的command样式ys_report,不覆盖已有样式。工厂函数创建命令对象;lammpsplugin_init提供名称、版本和工厂入口,再将它注册给当前进程的LAMMPS插件机制。
命令通过lammps_get_natoms公开C接口取全局原子数,只有MPI rank 0写文件,避免多个进程同时覆盖同一路径。它不修改原子、相互作用或其他用户文件。
sdk中包含与本例版本匹配的lammpsplugin.h和version.h,附带原许可证;其余公开头文件使用现有安装。换LAMMPS版本或编译环境时,应重新编译并核对API与ABI,而不是直接复制旧so。
3 实际构建脚本#
#!/bin/bash
set -eo pipefail
source /etc/profile
cd "$(dirname "$0")"
module purge
module load lammps/30Sep2026-p100-gpu
test ! -e build
mkdir build
mpicxx -O2 -fPIC -shared -std=c++17 -fopenmp -DLAMMPS_SMALLBIG -I/public/software/lammps/30Sep2026/p100/gpu/include/lammps -Isdk ys_report.cpp -o build/ysreportplugin.so
日常执行前面的提交脚本即可完成构建。若在已分配资源中单独编译,可执行:
bash build.sh
生成文件为build/ysreportplugin.so。插件源码与GPL许可都在资料包中,不需要修改公共LAMMPS安装目录。
4 完整LAMMPS输入#
plugin load ./ysreportplugin.so
units lj
atom_style atomic
lattice sc 1.0
region box block 0 2 0 2 0 2
create_box 1 box
create_atoms 1 box
mass 1 1.0
ys_report before-clear.json
plugin list
clear
ys_report after-clear.json
plugin unload command ys_report
plugin list
plugin load ./ysreportplugin.so
ys_report after-reload.json
plugin unload command ys_report
plugin list
plugin load载入当前工作目录的插件,ys_report文件名写出状态。这里先建立2×2×2个简单立方格点,共8个原子,再执行clear清空模型。
当前30Sep2026版本中,clear后插件仍然注册,ys_report可继续使用,此时原子数为0。plugin unload command ys_report显式卸载这一命令,再次load后它重新可用。
5 实际1/2 MPI进程结果#
| 阶段 | 1个MPI进程 | 2个MPI进程 |
|---|---|---|
| 建立模型后before-clear.json | 8原子 | 8原子 |
| clear后after-clear.json | 0原子 | 0原子 |
| 卸载后重新加载after-reload.json | 0原子 | 0原子 |
两进程情况下模型分布在MPI进程之间,但报告的是全局原子数。plugin list在首次载入后显示1个动态插件,在对应卸载后显示0;这些信息和完整输入保存在各自日志中。
cat work/one-rank/before-clear.json
cat work/one-rank/after-clear.json
cat work/two-rank/before-clear.json
cat work/two-rank/after-reload.json
grep -E "Loading plugin|Unloading command|Currently loaded plugins" work/two-rank/launcher.log
6 重新检查或扩展#
python3 check_results.py work
cat work/RESULTS.json
检查脚本逐项读取实际JSON和插件列表;查看本文参考运行时把work改成reference。扩展自己的命令时,可保留相同工厂和注册方式,修改command处理内容与名称,再用1/2 MPI进程检查并行行为。
插件机制支持的其他样式还需要各自的类接口与物理数值测试,本篇的命令插件不代替自定义pair/fix/compute的完整实现。接口说明见官方插件开发文档和plugin命令。