n2p2 - A neural network potential package
pair_hdnnp.cpp
Go to the documentation of this file.
1/* -*- c++ -*- ----------------------------------------------------------
2 LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
3 https://www.lammps.org/ Sandia National Laboratories
4 LAMMPS development team: developers@lammps.org
5
6 Copyright (2003) Sandia Corporation. Under the terms of Contract
7 DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
8 certain rights in this software. This software is distributed under
9 the GNU General Public License.
10
11 This file initially came from n2p2 (https://github.com/CompPhysVienna/n2p2)
12 Copyright (2018) Andreas Singraber (University of Vienna)
13
14 See the README file in the top-level LAMMPS directory.
15------------------------------------------------------------------------- */
16
17/* ----------------------------------------------------------------------
18 Contributing author: Andreas Singraber
19------------------------------------------------------------------------- */
20
21#include "pair_hdnnp.h"
22
23#include "atom.h"
24#include "citeme.h"
25#include "comm.h"
26#include "error.h"
27#include "memory.h"
28#include "neigh_list.h"
29#include "neighbor.h"
30#include "update.h"
31
32#include <cstring>
33
34#include "InterfaceLammps.h" // n2p2 interface header
35
36using namespace LAMMPS_NS;
37
38static const char cite_user_hdnnp_package[] =
39 "ML-HDNNP package: doi:10.1021/acs.jctc.8b00770\n\n"
40 "@Article{Singraber19,\n"
41 " author = {Singraber, Andreas and Behler, J{\"o}rg and Dellago, Christoph},\n"
42 " title = {Library-Based {LAMMPS} Implementation of High-Dimensional\n"
43 " Neural Network Potentials},\n"
44 " year = {2019},\n"
45 " month = mar,\n"
46 " volume = {15},\n"
47 " pages = {1827--1840},\n"
48 " doi = {10.1021/acs.jctc.8b00770},\n"
49 " journal = {J.~Chem.\\ Theory Comput.},\n"
50 " number = {3}\n"
51 "}\n\n";
52
53/* ---------------------------------------------------------------------- */
54
55PairHDNNP::PairHDNNP(LAMMPS *lmp) : Pair(lmp)
56{
57 if (lmp->citeme) lmp->citeme->add(cite_user_hdnnp_package);
58
59 single_enable = 0; // 1 if single() routine exists
60 restartinfo = 0; // 1 if pair style writes restart info
61 one_coeff = 1; // 1 if allows only one coeff * * call
62 manybody_flag = 1; // 1 if a manybody potential
63 unit_convert_flag =
64 0; // TODO: Check possible values. value != 0 indicates support for unit conversion.
65 reinitflag = 0; // 1 if compatible with fix adapt and alike
66
67 interface = new nnp::InterfaceLammps();
68}
69
70/* ---------------------------------------------------------------------- */
71
73{
74 delete interface;
75 memory->destroy(setflag);
76 memory->destroy(cutsq);
77}
78
79/* ---------------------------------------------------------------------- */
80
81void PairHDNNP::compute(int eflag, int vflag)
82{
83 ev_init(eflag, vflag);
84
85 // Set number of local atoms and add element.
86 interface->setLocalAtoms(atom->nlocal, atom->type);
87 // Transfer tags separately. Interface::setLocalTags is overloaded internally
88 // to work with both -DLAMMPS_SMALLBIG (tagint = int) and -DLAMMPS_BIGBIG
89 // (tagint = int64_t)
90 interface->setLocalTags(atom->tag);
91
92 // Transfer local neighbor list to n2p2 interface.
94
95 // Compute symmetry functions, atomic neural networks and add up energy.
97
98 // Do all stuff related to extrapolation warnings.
99 if (showew || showewsum > 0 || maxew >= 0) { handleExtrapolationWarnings(); }
100
101 // Calculate forces of local and ghost atoms.
102 interface->getForces(atom->f);
103
104 // Add energy contribution to total energy.
105 if (eflag_global)
106 ev_tally(0, 0, atom->nlocal, 1, interface->getEnergy(), 0.0, 0.0, 0.0, 0.0, 0.0);
107
108 // Add atomic energy if requested (CAUTION: no physical meaning!).
109 if (eflag_atom)
110 for (int i = 0; i < atom->nlocal; ++i) eatom[i] = interface->getAtomicEnergy(i);
111
112 // If virial needed calculate via F dot r.
113 if (vflag_fdotr) virial_fdotr_compute();
114}
115
116/* ----------------------------------------------------------------------
117 global settings
118------------------------------------------------------------------------- */
119
120void PairHDNNP::settings(int narg, char **arg)
121{
122 int iarg = 0;
123
124 if (narg < 1) error->all(FLERR, "Illegal pair_style command");
125
126 maxCutoffRadius = utils::numeric(FLERR, arg[0], false, lmp);
127 iarg++;
128
129 // default settings
130 directory = utils::strdup("hdnnp/");
131 showew = true;
132 showewsum = 0;
133 maxew = 0;
134 resetew = false;
135 cflength = 1.0;
136 cfenergy = 1.0;
139
140 while (iarg < narg) {
141 // set HDNNP directory
142 if (strcmp(arg[iarg], "dir") == 0) {
143 if (iarg + 2 > narg) error->all(FLERR, "Illegal pair_style command");
144 delete[] directory;
145 directory = utils::strdup(arg[iarg + 1]);
146 iarg += 2;
147 // show extrapolation warnings
148 } else if (strcmp(arg[iarg], "showew") == 0) {
149 if (iarg + 2 > narg) error->all(FLERR, "Illegal pair_style command");
150 showew = utils::logical(FLERR, arg[iarg + 1], false, lmp) == 1;
151 iarg += 2;
152 // show extrapolation warning summary
153 } else if (strcmp(arg[iarg], "showewsum") == 0) {
154 if (iarg + 2 > narg) error->all(FLERR, "Illegal pair_style command");
155 showewsum = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
156 iarg += 2;
157 // maximum allowed extrapolation warnings
158 } else if (strcmp(arg[iarg], "maxew") == 0) {
159 if (iarg + 2 > narg) error->all(FLERR, "Illegal pair_style command");
160 maxew = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
161 iarg += 2;
162 // reset extrapolation warning counter
163 } else if (strcmp(arg[iarg], "resetew") == 0) {
164 if (iarg + 2 > narg) error->all(FLERR, "Illegal pair_style command");
165 resetew = utils::logical(FLERR, arg[iarg + 1], false, lmp) == 1;
166 iarg += 2;
167 // length unit conversion factor
168 } else if (strcmp(arg[iarg], "cflength") == 0) {
169 if (iarg + 2 > narg) error->all(FLERR, "Illegal pair_style command");
170 cflength = utils::numeric(FLERR, arg[iarg + 1], false, lmp);
171 iarg += 2;
172 // energy unit conversion factor
173 } else if (strcmp(arg[iarg], "cfenergy") == 0) {
174 if (iarg + 2 > narg) error->all(FLERR, "Illegal pair_style command");
175 cfenergy = utils::numeric(FLERR, arg[iarg + 1], false, lmp);
176 iarg += 2;
177 } else
178 error->all(FLERR, "Illegal pair_style command");
179 }
180}
181
182/* ----------------------------------------------------------------------
183 set coeffs for one or more type pairs
184------------------------------------------------------------------------- */
185
186void PairHDNNP::coeff(int narg, char **arg)
187{
188 int n = atom->ntypes;
189
190 if (!allocated) allocate();
191
192 if (narg != 2 + n) error->all(FLERR, "Incorrect args for pair coefficients");
193
194 if (strcmp(arg[0], "*") != 0 || strcmp(arg[1], "*") != 0)
195 error->all(FLERR, "Incorrect args for pair coefficients");
196
197 int *map = new int[n + 1];
198 for (int i = 0; i < n; i++) map[i] = 0;
199
200 emap = "";
201 for (int i = 2; i < narg; i++) {
202 if (strcmp(arg[i], "NULL") != 0) {
203 if (!emap.empty()) emap += ",";
204 emap += std::to_string(i - 1) + ":" + arg[i];
205 map[i - 1] = 1;
206 }
207 }
208
209 int count = 0;
210 for (int i = 1; i <= n; i++)
211 for (int j = i; j <= n; j++)
212 if (map[i] > 0 && map[j] > 0) {
213 setflag[i][j] = 1;
214 count++;
215 }
216
217 if (count == 0) error->all(FLERR, "Incorrect args for pair coefficients");
218
219 delete[] map;
220}
221
222/* ----------------------------------------------------------------------
223 init specific to this pair style
224------------------------------------------------------------------------- */
225
227{
228 neighbor->add_request(this, NeighConst::REQ_FULL);
229
230 // Return immediately if HDNNP setup is already completed.
231 if (interface->isInitialized()) return;
232
233 // Activate screen and logfile output only for rank 0.
234 if (comm->me == 0) {
235 if (lmp->screen != nullptr) interface->log.registerCFilePointer(&(lmp->screen));
236 if (lmp->logfile != nullptr) interface->log.registerCFilePointer(&(lmp->logfile));
237 }
238
239 // Initialize interface on all processors.
241 cfenergy, maxCutoffRadius, atom->ntypes, comm->me);
242
243 // LAMMPS cutoff radius (given via pair_coeff) should not be smaller than
244 // maximum symmetry function cutoff radius.
245 if (maxCutoffRadius < interface->getMaxCutoffRadius())
246 error->all(FLERR, "Inconsistent cutoff radius");
247}
248
249/* ----------------------------------------------------------------------
250 init for one type pair i,j and corresponding j,i
251------------------------------------------------------------------------- */
252
253double PairHDNNP::init_one(int, int)
254{
255 return maxCutoffRadius;
256}
257
258/* ----------------------------------------------------------------------
259 allocate all arrays
260------------------------------------------------------------------------- */
261
263{
264 allocated = 1;
265 int n = atom->ntypes;
266
267 memory->create(setflag, n + 1, n + 1, "pair:setflag");
268 for (int i = 1; i <= n; i++)
269 for (int j = i; j <= n; j++) setflag[i][j] = 0;
270
271 memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); // TODO: Is this required?
272}
273
275{
276 // Transfer neighbor list to n2p2.
277 double rc2 = maxCutoffRadius * maxCutoffRadius;
278 for (int ii = 0; ii < list->inum; ++ii) {
279 int i = list->ilist[ii];
280 for (int jj = 0; jj < list->numneigh[i]; ++jj) {
281 int j = list->firstneigh[i][jj];
282 j &= NEIGHMASK;
283 double dx = atom->x[i][0] - atom->x[j][0];
284 double dy = atom->x[i][1] - atom->x[j][1];
285 double dz = atom->x[i][2] - atom->x[j][2];
286 double d2 = dx * dx + dy * dy + dz * dz;
287 if (d2 <= rc2) { interface->addNeighbor(i, j, atom->tag[j], atom->type[j], dx, dy, dz, d2); }
288 }
289 }
290}
291
293{
294 // Get number of extrapolation warnings for local atoms.
295 long numCurrentEW = (long) interface->getNumExtrapolationWarnings();
296
297 // Update (or set, resetew == true) total warnings counter.
298 if (resetew)
299 numExtrapolationWarningsTotal = numCurrentEW;
300 else
301 numExtrapolationWarningsTotal += numCurrentEW;
302
303 // Update warnings summary counter.
304 if (showewsum > 0) { numExtrapolationWarningsSummary += numCurrentEW; }
305
306 // If requested write extrapolation warnings.
307 // Requires communication of all symmetry functions statistics entries to
308 // rank 0.
309 if (showew > 0) {
310 // First collect an overview of extrapolation warnings per process.
311 long *numEWPerProc = nullptr;
312 if (comm->me == 0) numEWPerProc = new long[comm->nprocs];
313 MPI_Gather(&numCurrentEW, 1, MPI_LONG, numEWPerProc, 1, MPI_LONG, 0, world);
314
315 if (comm->me == 0) {
316 for (int i = 1; i < comm->nprocs; i++) {
317 if (numEWPerProc[i] > 0) {
318 long bs = 0;
319 MPI_Status ms;
320 // Get buffer size.
321 MPI_Recv(&bs, 1, MPI_LONG, i, 0, world, &ms);
322 auto buf = new char[bs];
323 // Receive buffer.
324 MPI_Recv(buf, bs, MPI_BYTE, i, 0, world, &ms);
325 interface->extractEWBuffer(buf, bs);
326 delete[] buf;
327 }
328 }
330 } else if (numCurrentEW > 0) {
331 // Get desired buffer length for all extrapolation warning entries.
332 long bs = interface->getEWBufferSize();
333 // Allocate and fill buffer.
334 auto buf = new char[bs];
335 interface->fillEWBuffer(buf, bs);
336 // Send buffer size and buffer.
337 MPI_Send(&bs, 1, MPI_LONG, 0, 0, world);
338 MPI_Send(buf, bs, MPI_BYTE, 0, 0, world);
339 delete[] buf;
340 }
341
342 if (comm->me == 0) delete[] numEWPerProc;
343 }
344
345 // If requested gather number of warnings to display summary.
346 if (showewsum > 0 && update->ntimestep % showewsum == 0) {
347 long globalEW = 0;
348 // Communicate the sum over all processors to proc 0.
349 MPI_Reduce(&numExtrapolationWarningsSummary, &globalEW, 1, MPI_LONG, MPI_SUM, 0, world);
350 // Write to screen or logfile.
351 if (comm->me == 0)
352 utils::logmesg(lmp, "### NNP EW SUMMARY ### TS: {:10d} EW {:10d} EWPERSTEP {:10.3e}\n",
353 update->ntimestep, globalEW, double(globalEW) / showewsum);
354 // Reset summary counter.
356 }
357
358 // Stop if maximum number of extrapolation warnings is exceeded.
360 error->one(FLERR, "Too many extrapolation warnings");
361 }
362
363 // Reset internal extrapolation warnings counters.
365}
long numExtrapolationWarningsSummary
Definition: pair_hdnnp.h:59
void init_style() override
Definition: pair_hdnnp.cpp:226
void handleExtrapolationWarnings()
Definition: pair_hdnnp.cpp:292
double init_one(int, int) override
Definition: pair_hdnnp.cpp:253
void compute(int, int) override
Definition: pair_hdnnp.cpp:81
void settings(int, char **) override
Definition: pair_hdnnp.cpp:120
std::string emap
Definition: pair_hdnnp.h:64
virtual void allocate()
Definition: pair_hdnnp.cpp:262
void coeff(int, char **) override
Definition: pair_hdnnp.cpp:186
long numExtrapolationWarningsTotal
Definition: pair_hdnnp.h:58
nnp::InterfaceLammps * interface
Definition: pair_hdnnp.h:65
long getEWBufferSize() const
Calculate buffer size for extrapolation warning communication.
void process()
Calculate symmetry functions, atomic neural networks and sum of local energy contributions.
void extractEWBuffer(char const *const &buf, int bs)
Extract given buffer to symmetry function statistics class.
void setLocalTags(int const *const atomTag)
Set atom tags (int version, -DLAMMPS_SMALLBIG).
double getEnergy() const
Return sum of local energy contributions.
void fillEWBuffer(char *const &buf, int bs) const
Fill provided buffer with extrapolation warning entries.
double getAtomicEnergy(int index) const
Return energy contribution of one atom.
void getForces(double *const *const &atomF) const
Calculate forces and add to LAMMPS atomic force arrays.
void initialize(char const *const &directory, char const *const &emap, bool showew, bool resetew, int showewsum, int maxew, double cflength, double cfenergy, double lammpsCutoff, int lammpsNtypes, int myRank)
Initialize the LAMMPS interface.
bool isInitialized() const
Check if this interface is correctly initialized.
void writeExtrapolationWarnings()
Write extrapolation warnings to log.
void setLocalAtoms(int numAtomsLocal, int const *const atomType)
(Re)set structure to contain only local LAMMPS atoms.
void clearExtrapolationWarnings()
Clear extrapolation warnings storage.
void addNeighbor(int i, int j, int64_t tag, int type, double dx, double dy, double dz, double d2)
Add one neighbor to atom (int64_t version, -DLAMMPS_BIGBIG).
void registerCFilePointer(FILE **const &filePointer)
Register new C-style FILE* pointer for output.
Definition: Log.cpp:85
std::size_t getNumExtrapolationWarnings() const
Count total number of extrapolation warnings encountered for all elements and symmetry functions.
Definition: Mode.cpp:2166
Log log
Global log file.
Definition: Mode.h:593
Definition: Atom.h:29
static const char cite_user_hdnnp_package[]
Definition: pair_hdnnp.cpp:38