Skip to content

Commit 47e9ec3

Browse files
committed
update toolchain and document
1 parent 29ba84c commit 47e9ec3

File tree

12 files changed

+338
-35
lines changed

12 files changed

+338
-35
lines changed

CMakeLists.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -650,13 +650,13 @@ if(DEFINED DeePMD_DIR)
650650
endif()
651651
endif()
652652

653-
option(ENABLE_NEPCPU "Enable NEP calculations on CPU" OFF)
654-
if(ENABLE_NEPCPU)
655-
message(STATUS "NEP support enabled.")
656-
include_directories(/home/mosey/devs/NEP_CPU/src/)
657-
link_directories(/home/mosey/devs/NEP_CPU/src/)
658-
add_compile_definitions(__NEP)
659-
target_link_libraries(${ABACUS_BIN_NAME} /home/mosey/devs/NEP_CPU/src/libnep_cpu.so)
653+
if(DEFINED NEP_DIR)
654+
find_package(NEP REQUIRED)
655+
656+
if(NEP_FOUND)
657+
add_compile_definitions(__NEP)
658+
target_link_libraries(${ABACUS_BIN_NAME} NEP::nep_cpu)
659+
endif()
660660
endif()
661661

662662
if(DEFINED TensorFlow_DIR)

cmake/FindNEP.cmake

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
###############################################################################
2+
# - Find NEP_CPU
3+
# Finds the NEP_CPU header and library.
4+
#
5+
# This module will search for the NEP_CPU library, looking for a hint
6+
# from the NEP_DIR environment variable or CMake variable.
7+
#
8+
# This module defines the following variables:
9+
#
10+
# NEP_FOUND - True if the NEP_CPU library and headers were found.
11+
# NEP_INCLUDE_DIR - The directory where nep.h is located.
12+
# NEP_LIBRARY - The full path to the NEP_CPU library.
13+
#
14+
# It also defines the following imported target:
15+
#
16+
# NEP::nep_cpu - The NEP_CPU library target.
17+
#
18+
###############################################################################
19+
20+
find_path(NEP_INCLUDE_DIR nep.h
21+
HINTS ${NEP_DIR}
22+
PATH_SUFFIXES "include"
23+
)
24+
25+
find_library(NEP_LIBRARY
26+
NAMES nepcpu
27+
HINTS ${NEP_DIR}
28+
PATH_SUFFIXES "lib"
29+
)
30+
31+
include(FindPackageHandleStandardArgs)
32+
find_package_handle_standard_args(NEP
33+
DEFAULT_MSG
34+
NEP_LIBRARY NEP_INCLUDE_DIR)
35+
36+
if(NEP_FOUND)
37+
if(NOT TARGET NEP::nep_cpu)
38+
add_library(NEP::nep_cpu UNKNOWN IMPORTED)
39+
set_target_properties(NEP::nep_cpu PROPERTIES
40+
IMPORTED_LOCATION "${NEP_LIBRARY}"
41+
INTERFACE_INCLUDE_DIRECTORIES "${NEP_INCLUDE_DIR}"
42+
)
43+
endif()
44+
endif()
45+
46+
mark_as_advanced(NEP_INCLUDE_DIR NEP_LIBRARY)

docs/advanced/input_files/input-main.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ These variables are used to control general system parameters.
532532
- tddft: real-time time-dependent density functional theory (TDDFT)
533533
- lj: Leonard Jones potential
534534
- dp: DeeP potential, see details in [md.md](../md.md#dpmd)
535+
- nep: Neuroevolution Potential, see details in [md.md](../md.md#nep)
535536
- ks-lr: Kohn-Sham density functional theory + LR-TDDFT (Under Development Feature)
536537
- lr: LR-TDDFT with given KS orbitals (Under Development Feature)
537538
- **Default**: ksdft

docs/advanced/install.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ Similarly, DeePMD-kit supports PyTorch backend but its libraries are placed at a
5555
cmake -B build -DDeePMD_DIR=/dir_to_deepmd-kit -DTorch_DIR=/dir_to_pytorch
5656
```
5757

58+
## Build with NEP
59+
This interface enables running MD simulations with the NEP model. It requires the [NEP_CPU](https://github.com/brucefan1983/NEP_CPU) library, which can be easily installed using toolchain as shown below:
60+
```bash
61+
./install_abacus_toolchain.sh --with-nepcpu=install
62+
```
63+
64+
To build ABACUS:
65+
```bash
66+
cmake -B build -DNEP_DIR=/path/to/nep_cpu
67+
```
68+
5869
## Build with LibRI and LibComm
5970

6071
The new EXX implementation depends on two external libraries:

docs/advanced/md.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,8 @@ ABACUS performs the [Multi-Scale Shock Technique (MSST) integration](https://jou
8787
Compiling ABACUS with [DeePMD-kit](https://github.com/deepmodeling/deepmd-kit), MD calculations based on machine learning DP model is enabled.
8888

8989
To employ DPMD calculations, [esolver_type](./input_files/input-main.md#esolver_type) should be set to `dp`.
90-
And the filename of DP model is specified by keyword [pot_file](./input_files/input-main.md#pot_file).
90+
And the filename of DP model is specified by keyword [pot_file](./input_files/input-main.md#pot_file).
91+
92+
## NEP
93+
94+
If ABACUS is compiled with the Neuroevolution Potential ([NEP](https://gpumd.org/potentials/nep.html)), MD simulations using NEP models are enabled. To use this feature, set [esolver_type](./input_files/input-main.md#esolver_type) to `nep` and specify the potential file path with the [pot_file](./input_files/input-main.md#pot_file) keyword in your INPUT file.

source/source_esolver/esolver_nep.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
1+
/**
2+
* @file esolver_nep.cpp
3+
#include "source_io/module_parameter/parameter.h"
4+
* @brief Implementation of ESolver_NEP class for neuroevolution potential (NEP).
5+
*
6+
* This file contains the implementation of the ESolver_NEP class, which is used for solving the energy and forces in a
7+
* NEP simulation.
8+
* NEP is a method for training deep neural networks to accurately predict the potential energy surface of a
9+
* molecular system.
10+
*
11+
* For more information about NEP, see the following reference:
12+
* 1. https://gpumd.org/potentials/nep.html
13+
* 2. https://doi.org/10.1002/mgea.70028
14+
*
15+
* @author MoseyQAQ
16+
* @date 2025-10-10
17+
*/
118
#include "esolver_nep.h"
19+
220
#include "source_base/parallel_common.h"
321
#include "source_base/timer.h"
422
#include "source_io/output_log.h"
523
#include "source_io/cif_io.h"
24+
625
#include <numeric>
726
#include <unordered_map>
827

928
using namespace ModuleESolver;
1029

11-
ESolver_NEP::ESolver_NEP(const std::string& pot_file): nep(pot_file)
12-
{
13-
classname = "ESolver_NEP";
14-
nep_file = pot_file;
15-
}
16-
1730
void ESolver_NEP::before_all_runners(UnitCell& ucell, const Input_para& inp)
1831
{
1932
nep_potential = 0.0;
2033
nep_force.create(ucell.nat, 3);
2134
nep_virial.create(3, 3);
35+
atype.resize(ucell.nat);
2236
_e.resize(ucell.nat);
2337
_f.resize(3 * ucell.nat);
2438
_v.resize(9 * ucell.nat);
@@ -28,10 +42,8 @@ void ESolver_NEP::before_all_runners(UnitCell& ucell, const Input_para& inp)
2842
"# Generated by ABACUS ModuleIO::CifParser",
2943
"data_?");
3044

31-
atype.resize(ucell.nat);
32-
3345
#ifdef __NEP
34-
/// determine the type map from STRU to DP model
46+
/// determine the type map from STRU to NEP model
3547
type_map(ucell);
3648
#endif
3749
}
@@ -96,7 +108,7 @@ void ESolver_NEP::runner(UnitCell& ucell, const int istep)
96108
nep_force(i, 2) = _f[i + 2 * nat] * fact_f;
97109
}
98110

99-
// get the total virial by summing over all atomic contributions
111+
// virial
100112
std::vector<double> v_sum(9, 0.0);
101113
for (int j = 0; j < 9; ++j)
102114
{
@@ -107,7 +119,7 @@ void ESolver_NEP::runner(UnitCell& ucell, const int istep)
107119
}
108120
}
109121

110-
// transform to stress tensor
122+
// virial -> stress
111123
for (int i = 0; i < 3; ++i)
112124
{
113125
for (int j = 0; j < 3; ++j)
@@ -156,12 +168,13 @@ void ESolver_NEP::after_all_runners(UnitCell& ucell)
156168

157169
#ifdef __NEP
158170
void ESolver_NEP::type_map(const UnitCell& ucell)
159-
{
171+
{
172+
// parse the element list from NEP model file
160173
std::unordered_map<std::string, int> label;
161174
std::string temp;
162175
for (int i = 0; i < nep.element_list.size(); ++i)
163176
{
164-
label[nep.element_list[i]] = i;
177+
label[nep.element_list[i]] = i; //> label: map from element string to index int.
165178
}
166179

167180
std::cout << "\n Element list of model file " << nep_file << " " << std::endl;
@@ -180,6 +193,7 @@ void ESolver_NEP::type_map(const UnitCell& ucell)
180193
}
181194
std::cout << "\n -----------------------------------------------------------------" << std::endl;
182195

196+
// parse the atype based on the element list
183197
int iat = 0;
184198
for (int it = 0; it < ucell.ntype; ++it)
185199
{

source/source_esolver/esolver_nep.h

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,93 @@ namespace ModuleESolver
1414
class ESolver_NEP : public ESolver
1515
{
1616
public:
17-
ESolver_NEP(const std::string& pot_file);
17+
#ifdef __NEP
18+
ESolver_NEP(const std::string& pot_file): nep(pot_file)
19+
{
20+
classname = "ESolver_NEP";
21+
nep_file = pot_file;
22+
}
23+
#else
24+
ESolver_NEP(const std::string& pot_file)
25+
{
26+
classname = "ESolver_NEP";
27+
nep_file = pot_file;
28+
}
29+
#endif
1830

31+
/**
32+
* @brief Initialize the NEP solver with given input parameters and unit cell
33+
*
34+
* @param inp input parameters
35+
* @param cell unitcell information
36+
*/
1937
void before_all_runners(UnitCell& ucell, const Input_para& inp) override;
38+
39+
/**
40+
* @brief Run the NEP solver for a given ion/md step and unit cell
41+
*
42+
* @param istep the current ion/md step
43+
* @param cell unitcell information
44+
*/
2045
void runner(UnitCell& ucell, const int istep) override;
46+
47+
/**
48+
* @brief get the total energy without ion kinetic energy
49+
*
50+
* @param etot the computed energy
51+
* @return total energy without ion kinetic energy
52+
*/
2153
double cal_energy() override;
54+
55+
/**
56+
* @brief get the computed atomic forces
57+
*
58+
* @param force the computed atomic forces
59+
*/
2260
void cal_force(UnitCell& ucell, ModuleBase::matrix& force) override;
61+
62+
/**
63+
* @brief get the computed lattice virials
64+
*
65+
* @param stress the computed lattice virials
66+
*/
2367
void cal_stress(UnitCell& ucell, ModuleBase::matrix& stress) override;
68+
69+
/**
70+
* @brief Prints the final total energy of the NEP model to the output file
71+
*
72+
* This function prints the final total energy of the NEP model in eV to the output file along with some formatting.
73+
*/
2474
void after_all_runners(UnitCell& ucell) override;
2575

2676
private:
77+
/**
78+
* @brief determine the type map of NEP model
79+
*
80+
* @param ucell unitcell information
81+
*/
2782
void type_map(const UnitCell& ucell);
83+
84+
/**
85+
* @brief NEP related variables for ESolver_NEP class
86+
*
87+
* These variables are related to the NEP method and are used in the ESolver_NEP class to compute the potential
88+
* energy and forces.
89+
*
90+
* @note These variables are only defined if the __NEP preprocessor macro is defined.
91+
*/
2892
#ifdef __NEP
29-
NEP3 nep;
93+
NEP3 nep; ///< NEP3 object for NEP calculations
3094
#endif
31-
std::string nep_file;
32-
std::vector<int> atype = {};
33-
double nep_potential;
34-
ModuleBase::matrix nep_force;
35-
ModuleBase::matrix nep_virial;
36-
std::vector<double> _e;
37-
std::vector<double> _f;
38-
std::vector<double> _v;
95+
96+
std::string nep_file; ///< directory of NEP model file
97+
std::vector<int> atype = {}; ///< atom type mapping for NEP model
98+
double nep_potential; ///< computed potential energy
99+
ModuleBase::matrix nep_force; ///< computed atomic forces
100+
ModuleBase::matrix nep_virial; ///< computed lattice virials
101+
std::vector<double> _e; ///< temporary storage for energy computation
102+
std::vector<double> _f; ///< temporary storage for force computation
103+
std::vector<double> _v; ///< temporary storage for virial computation
39104
};
40105

41106
} // namespace ModuleESolver

source/source_io/read_input_item_system.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void ReadInput::item_system()
121121
{
122122
if (access(para.input.mdp.pot_file.c_str(), 0) == -1)
123123
{
124-
ModuleBase::WARNING_QUIT("ReadInput", "Can not find DP model !");
124+
ModuleBase::WARNING_QUIT("ReadInput", "Can not find `pot_file` !");
125125
}
126126
}
127127
};

toolchain/build_abacus_intel.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ cmake -B $BUILD_DIR -DCMAKE_INSTALL_PREFIX=$PREFIX \
4848
-DENABLE_RAPIDJSON=ON \
4949
-DRapidJSON_DIR=$RAPIDJSON \
5050
-DLIBRI_DIR=$LIBRI \
51-
-DLIBCOMM_DIR=$LIBCOMM \
52-
-DENABLE_NEPCPU=ON
51+
-DLIBCOMM_DIR=$LIBCOMM
5352
# -DENABLE_MLALGO=1 \
5453
# -DTorch_DIR=$LIBTORCH \
5554
# -Dlibnpy_INCLUDE_DIR=$LIBNPY \

toolchain/install_abacus_toolchain.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ The --with-PKG options follow the rules:
211211
Default = no
212212
--with-libcomm Enable LibComm for higher-level methods like hybrid functionals, RPA or GW
213213
Default = no
214+
--with-nepcpu Enable NEP (CPU version) for machine learning potentials
215+
Default = no
214216
215217
FURTHER INSTRUCTIONS
216218
@@ -246,7 +248,7 @@ EOF
246248
tool_list="gcc intel amd cmake"
247249
mpi_list="mpich openmpi intelmpi"
248250
math_list="mkl aocl openblas"
249-
lib_list="fftw libxc scalapack elpa cereal rapidjson libtorch libnpy libri libcomm"
251+
lib_list="fftw libxc scalapack elpa cereal rapidjson libtorch libnpy libri libcomm nepcpu"
250252
package_list="${tool_list} ${mpi_list} ${math_list} ${lib_list}"
251253
# ------------------------------------------------------------------------
252254

@@ -596,6 +598,9 @@ while [ $# -ge 1 ]; do
596598
--with-libcomm*)
597599
with_libcomm=$(read_with "${1}")
598600
;;
601+
--with-nepcpu*)
602+
with_nepcpu=$(read_with "${1}")
603+
;;
599604
--help*)
600605
show_help
601606
exit 0

0 commit comments

Comments
 (0)