eOn client
Long-timescale dynamics: aKMC, NEB, parallel replica
☾
Toggle main menu visibility
Loading...
Searching...
No Matches
LAMMPSPot.cpp
Go to the documentation of this file.
1
/*
2
** This file is part of eOn.
3
**
4
** SPDX-License-Identifier: BSD-3-Clause
5
**
6
** Copyright (c) 2010--present, eOn Development Team
7
** All rights reserved.
8
**
9
** Repo:
10
** https://github.com/TheochemUI/eOn
11
*/
12
#include "
eon/potentials/LAMMPS/LAMMPSPot.h
"
13
#include "
eon/EonLogger.h
"
14
#include "
eon/fpe_handler.h
"
15
#include "
eon/potentials/LAMMPS/LammpsLoader.h
"
16
17
#include <cmath>
18
#include <cstring>
19
#include <filesystem>
20
#include <format>
21
#include <fstream>
22
#include <map>
23
#include <string>
24
25
#if !defined(EONMPI) && !defined(IS_WINDOWS)
26
#include <cerrno>
27
#include <cstdlib>
28
#include <vector>
29
30
#include <csignal>
31
#include <poll.h>
32
#include <sys/wait.h>
33
#include <unistd.h>
34
#endif
35
36
#ifdef EONMPI
37
#define LAMMPS_LIB_MPI
38
#endif
39
40
LAMMPSPot::LAMMPSPot
(
const
Parameters
&p)
41
:
Potential
(p),
42
lammpsThr
{p.potential_options.LAMMPSThreads}
43
#ifdef EONMPI
44
,
45
mpiComm{p.potential_options.MPIClientComm}
46
#endif
47
{
48
// Fail fast if LAMMPS library not available
49
eonc::LammpsLoader::instance
().
require_loaded
();
50
#if !defined(EONMPI) && !defined(IS_WINDOWS)
51
// Fork the worker NOW, at construction, before this process ever opens a
52
// LAMMPS instance (and thus before liblammps initialises MPI). Open MPI
53
// does not support using MPI in a process that called MPI_Init before fork,
54
// so the worker must be spawned from a still-MPI-clean parent. Every
55
// LAMMPSPot -- endpoints and per-image alike -- runs its LAMMPS in its own
56
// child process, so the parent never initialises MPI at all.
57
ensureWorker
();
58
#endif
59
}
60
61
LAMMPSPot::~LAMMPSPot
() {
cleanMemory
(); }
62
63
void
LAMMPSPot::cleanMemory
() {
64
#if !defined(EONMPI) && !defined(IS_WINDOWS)
65
stopWorker
();
66
#endif
67
if
(
LAMMPSObj
!=
nullptr
) {
68
eonc::LammpsLoader::instance
().
close
(
LAMMPSObj
);
69
LAMMPSObj
=
nullptr
;
70
}
71
}
72
73
#if !defined(EONMPI) && !defined(IS_WINDOWS)
74
// ---------------------------------------------------------------------------
75
// Process-per-image worker plumbing (POSIX only)
76
// ---------------------------------------------------------------------------
77
namespace
{
78
// Report a geometry the worker could not evaluate as an impassable wall.
79
//
80
// Every failure path here used to throw, and nothing between the potential
81
// call and main catches it, so the client terminated. That loses the whole
82
// job, including searches that had already converged: a copper V/SIA search
83
// reached a saddle at 0.082 eV with a force of 0.027 eV/A and a curvature of
84
// -0.47, then died on the next evaluation before the result was written.
85
//
86
// A large finite energy with zeroed forces reads to the optimiser as a wall,
87
// so it backs out of the step and the search abandons this configuration and
88
// carries on. Callers stop the worker first; ensureWorker respawns it on the
89
// next evaluation.
90
void
rejectGeometry(
double
*U,
double
*F,
long
N) {
91
*U = 1.0e6;
92
// Zero forces would be read as convergence: an optimiser judges a point
93
// converged on force magnitude alone, so a rejected geometry with no force
94
// is accepted as a minimum and the wall energy is recorded as that
95
// minimum's energy. It then reaches the barrier as E_saddle - 1e6, which
96
// eOn reports as a negative barrier and discards -- a real 0.062 eV copper
97
// saddle was lost exactly this way. Return a force far above any
98
// convergence threshold so the point can never be mistaken for a
99
// stationary one, alternating its sign so the frame gains no net force.
100
for
(
long
i = 0; i < 3 * N; ++i) {
101
F[i] = 0.0;
102
}
103
for
(
long
i = 0; i < N; ++i) {
104
F[3 * i] = (i % 2 == 0) ? 1.0 : -1.0;
105
}
106
}
107
108
// Blocking read/write of exactly n bytes over a pipe. Returns false on EOF or
109
// error, so a dead peer is detected rather than silently producing garbage.
110
bool
readExact(
int
fd,
void
*buf,
size_t
n) {
111
auto
*p =
static_cast<
char
*
>
(buf);
112
while
(n > 0) {
113
ssize_t r = read(fd, p, n);
114
if
(r <= 0) {
115
if
(r < 0 && errno == EINTR)
116
continue
;
117
return
false
;
118
}
119
p += r;
120
n -=
static_cast<
size_t
>
(r);
121
}
122
return
true
;
123
}
124
bool
writeExact(
int
fd,
const
void
*buf,
size_t
n) {
125
const
auto
*p =
static_cast<
const
char
*
>
(buf);
126
while
(n > 0) {
127
ssize_t w = write(fd, p, n);
128
if
(w < 0) {
129
if
(errno == EINTR)
130
continue
;
131
return
false
;
132
}
133
p += w;
134
n -=
static_cast<
size_t
>
(w);
135
}
136
return
true
;
137
}
138
}
// namespace
139
140
void
LAMMPSPot::ensureWorker
() {
141
if
(
workerSpawned
)
142
return
;
143
144
int
reqPipe[2];
// parent -> child
145
int
resPipe[2];
// child -> parent
146
if
(pipe(reqPipe) != 0 || pipe(resPipe) != 0) {
147
throw
std::runtime_error(
"LAMMPSPot: failed to create worker pipes"
);
148
}
149
150
// Fork BEFORE opening any LAMMPS instance in this process, so MPI is first
151
// initialised inside the child. Each child is its own process with its own
152
// MPI_COMM_WORLD; concurrent children never share a communicator.
153
pid_t pid = fork();
154
if
(pid < 0) {
155
throw
std::runtime_error(
"LAMMPSPot: fork for worker failed"
);
156
}
157
158
if
(pid == 0) {
159
// Child: keep reqPipe read end and resPipe write end.
160
close(reqPipe[1]);
161
close(resPipe[0]);
162
reqFd
= reqPipe[0];
163
resFd
= resPipe[1];
164
// Client main arms feenableexcept unconditionally. The worker inherits
165
// that mask; LAMMPS EAM (PairEAM::compute) performs IEEE divisions that
166
// can raise FE_DIVBYZERO on near-coincident pairs during saddle / product
167
// minimisations. Under trapping that SIGFPEs, and the continue handler
168
// without MXCSR masking re-storms forever in the child (GB of identical
169
// "FPE (continuing)" lines). External pot code expects soft IEEE defaults;
170
// demote trapping for the whole worker process before any LAMMPS call.
171
eonc::disableFPE
();
172
runWorkerLoop
();
// never returns
173
}
174
175
// Parent: keep reqPipe write end and resPipe read end.
176
//
177
// Writing to a worker that has already exited raises SIGPIPE, whose default
178
// action kills the client outright -- before writeExact can return the
179
// error the caller is written to handle. A search that had converged on a
180
// saddle at 0.062 eV died this way with signal 13 as its endpoints were
181
// about to be minimised. Ignoring it turns the same condition into an
182
// EPIPE return, which reaches the geometry-rejection path and respawns.
183
std::signal(SIGPIPE, SIG_IGN);
184
close(reqPipe[0]);
185
close(resPipe[1]);
186
reqFd
= reqPipe[1];
187
resFd
= resPipe[0];
188
workerPid
= pid;
189
workerSpawned
=
true
;
190
}
191
192
void
LAMMPSPot::runWorkerLoop
() {
193
// Running in the forked child. Evaluate forces with an in-process LAMMPS
194
// (this child's own MPI_COMM_WORLD) and stream results back to the parent.
195
for
(;;) {
196
long
N = 0;
197
if
(!readExact(
reqFd
, &N,
sizeof
(N))) {
198
_exit(0);
// request pipe closed -> shut down cleanly
199
}
200
if
(N < 0) {
201
_exit(0);
// explicit shutdown sentinel from stopWorker()
202
}
203
std::vector<int> atomicNrs(
static_cast<
size_t
>
(N));
204
std::vector<double> R(
static_cast<
size_t
>
(3 * N));
205
double
box[9];
206
if
(!readExact(
reqFd
, atomicNrs.data(),
207
sizeof
(
int
) *
static_cast<
size_t
>
(N)) ||
208
!readExact(
reqFd
, box,
sizeof
(box)) ||
209
!readExact(
reqFd
, R.data(),
210
sizeof
(
double
) *
static_cast<
size_t
>
(3 * N))) {
211
_exit(1);
212
}
213
214
std::vector<double> F(
static_cast<
size_t
>
(3 * N), 0.0);
215
double
U = 0.0;
216
int
status = 0;
217
try
{
218
forceLocal
(N, R.data(), atomicNrs.data(), F.data(), &U, box);
219
}
catch
(...) {
220
status = 1;
221
}
222
223
if
(!writeExact(
resFd
, &status,
sizeof
(status)) ||
224
!writeExact(
resFd
, &U,
sizeof
(U)) ||
225
!writeExact(
resFd
, F.data(),
226
sizeof
(
double
) *
static_cast<
size_t
>
(3 * N))) {
227
_exit(1);
228
}
229
}
230
}
231
232
void
LAMMPSPot::stopWorker
() {
233
if
(!
workerSpawned
)
234
return
;
235
if
(
reqFd
>= 0) {
236
// Send an explicit shutdown sentinel, then close. A sentinel (rather than
237
// relying on pipe EOF) guarantees the child exits even when sibling worker
238
// processes hold an inherited copy of this write end.
239
long
sentinel = -1;
240
writeExact(
reqFd
, &sentinel,
sizeof
(sentinel));
241
close(
reqFd
);
242
reqFd
= -1;
243
}
244
if
(
resFd
>= 0) {
245
close(
resFd
);
246
resFd
= -1;
247
}
248
if
(
workerPid
> 0) {
249
// A wedged worker never acts on the sentinel or the closed pipe, and an
250
// unconditional wait then blocks the client forever at no CPU cost -- the
251
// hang this teardown exists to avoid. Give the child a brief chance to
252
// exit on its own, then insist.
253
int
st = 0;
254
bool
reaped =
false
;
255
for
(
int
i = 0; i < 100; ++i) {
// up to ~1 s
256
pid_t r = waitpid(
workerPid
, &st, WNOHANG);
257
if
(r ==
workerPid
|| r < 0) {
258
reaped =
true
;
259
break
;
260
}
261
usleep(10000);
262
}
263
if
(!reaped) {
264
kill(
workerPid
, SIGKILL);
265
waitpid(
workerPid
, &st, 0);
266
}
267
workerPid
= -1;
268
}
269
workerSpawned
=
false
;
270
}
271
#endif
// !EONMPI && !IS_WINDOWS
272
273
void
LAMMPSPot::force
(
long
N,
const
double
*R,
const
int
*atomicNrs,
double
*F,
274
double
*U,
double
*variance,
const
double
*box) {
275
variance =
nullptr
;
276
277
#ifdef EONMPI
278
forceLocal
(N, R, atomicNrs, F, U, box);
279
#elif defined(IS_WINDOWS)
280
// No fork/pipe on Windows; call forceLocal directly.
281
forceLocal
(N, R, atomicNrs, F, U, box);
282
#else
283
// Drive the dedicated worker process so this image's LAMMPS runs in its own
284
// process (own MPI_COMM_WORLD). Per-image NEB threads thus evaluate forces
285
// as truly concurrent processes with no shared-communicator contention.
286
std::lock_guard<std::mutex> workerLock(
workerMutex
);
287
if
(
workerRespawnsLeft
<= 0) {
288
rejectGeometry(U, F, N);
289
return
;
290
}
291
ensureWorker
();
292
293
if
(!writeExact(
reqFd
, &N,
sizeof
(N)) ||
294
!writeExact(
reqFd
, atomicNrs,
sizeof
(
int
) *
static_cast<
size_t
>
(N)) ||
295
!writeExact(
reqFd
, box,
sizeof
(
double
) * 9) ||
296
!writeExact(
reqFd
, R,
sizeof
(
double
) *
static_cast<
size_t
>
(3 * N))) {
297
// A worker stopped by an earlier rejected geometry leaves the request
298
// pipe closed, so the first send after it fails. Respawning happens on
299
// the next evaluation; reject this one rather than end the client.
300
--
workerRespawnsLeft
;
301
EONC_LOG_WARNING
(
"[LAMMPSPot] send to worker failed; {} respawns left "
302
"(eon-7416)"
,
303
workerRespawnsLeft
);
304
stopWorker
();
305
rejectGeometry(U, F, N);
306
return
;
307
}
308
309
// eon-7416: a worker stuck on a pathological geometry (LAMMPS spinning, or
310
// a NaN it never returns) would make the blocking read below hang until the
311
// akmc pass times out. Bound the wait: if the worker is silent past a
312
// generous per-eval deadline, kill and reap it (a stuck worker never reaches
313
// EOF, so a plain waitpid would block too) and fail this evaluation so the
314
// search discards the geometry; ensureWorker respawns on the next call.
315
{
316
struct
pollfd pfd;
317
pfd.fd =
resFd
;
318
pfd.events = POLLIN;
319
pfd.revents = 0;
320
int
pr = poll(&pfd, 1, 90000);
// 90 s: orders beyond a normal force eval
321
if
(pr <= 0) {
322
if
(
workerPid
> 0) {
323
kill(
workerPid
, SIGKILL);
324
}
325
--
workerRespawnsLeft
;
326
EONC_LOG_WARNING
(
327
"[LAMMPSPot] worker force eval timed out; {} respawns left "
328
"(eon-7416)"
,
329
workerRespawnsLeft
);
330
stopWorker
();
331
rejectGeometry(U, F, N);
332
return
;
333
}
334
}
335
int
status = 0;
336
if
(!readExact(
resFd
, &status,
sizeof
(status)) ||
337
!readExact(
resFd
, U,
sizeof
(
double
)) ||
338
!readExact(
resFd
, F,
sizeof
(
double
) *
static_cast<
size_t
>
(3 * N))) {
339
--
workerRespawnsLeft
;
340
EONC_LOG_WARNING
(
341
"[LAMMPSPot] worker died during force eval; {} respawns left "
342
"(eon-7416)"
,
343
workerRespawnsLeft
);
344
stopWorker
();
345
rejectGeometry(U, F, N);
346
return
;
347
}
348
if
(status != 0) {
349
--
workerRespawnsLeft
;
350
EONC_LOG_WARNING
(
351
"[LAMMPSPot] worker reported an evaluation error; {} respawns left "
352
"(eon-7416)"
,
353
workerRespawnsLeft
);
354
stopWorker
();
355
rejectGeometry(U, F, N);
356
return
;
357
}
358
// A saddle search that never terminates silently truncates the event
359
// table: the KMC residence time is 1/sum_j k_j over the discovered
360
// mechanisms, so a dropped search removes a term and biases the clock
361
// (Pedersen and Jónsson, Math. Comput. Simul. 80, 1487 (2010),
362
// doi:10.1016/j.matcom.2009.02.010, Fig. 1; Alexander and Schuh,
363
// Modelling Simul. Mater. Sci. Eng. 24, 065014 (2016),
364
// doi:10.1088/0965-0393/24/6/065014, on catalog completeness).
365
// An over-aggressive saddle-search kick can drive atoms on top of
366
// each other; the EAM force overflows to NaN/Inf and LAMMPS returns it
367
// rather than crashing. The min-mode search then spins on non-finite
368
// gradients until the akmc pass times out (0 processes). Reject the
369
// evaluation so the search discards that displacement and continues.
370
// Reject the geometry, not the process. Nothing between this call and
371
// main catches a throw here, so the client terminates: a search that was
372
// making progress is lost, and every other search sharing the pass goes
373
// with it. A large finite energy with zeroed forces reads to the
374
// optimiser as an impassable wall, so it backs out of the step and the
375
// search abandons this configuration and carries on.
376
bool
nonfinite = !std::isfinite(*U);
377
for
(
long
i = 0; i < 3 * N && !nonfinite; ++i) {
378
nonfinite = !std::isfinite(F[i]);
379
}
380
if
(nonfinite) {
381
EONC_LOG_WARNING
(
"[LAMMPSPot] non-finite force or energy; rejecting "
382
"geometry (eon-7416)"
);
383
rejectGeometry(U, F, N);
384
}
385
#endif
386
}
387
388
void
LAMMPSPot::forceLocal
(
long
N,
const
double
*R,
const
int
*atomicNrs,
389
double
*F,
double
*U,
const
double
*box) {
390
// Same contract as ASE / Metatomic: external pot libraries are not written
391
// for FE traps. Cover in-process (EONMPI / Windows) and any path that still
392
// has trapping armed when forceLocal runs. Always restore so FE traps do not
393
// stay demoted for the rest of the process after the first force call.
394
eonc::FPEHandler
fpeh;
395
fpeh.
eat_fpe
();
396
try
{
397
auto
&lmp =
eonc::LammpsLoader::instance
();
398
399
bool
newLammps =
false
;
400
for
(
int
i = 0; i < 9; i++) {
401
if
(
oldBox
[i] != box[i])
402
newLammps =
true
;
403
}
404
if
(
numberOfAtoms
!= N)
405
newLammps =
true
;
406
if
(newLammps) {
407
makeNewLAMMPS
(N, R, atomicNrs, box);
408
}
409
if
(!
LAMMPSObj
) {
410
throw
std::runtime_error(
"Should have a LAMMPS instance by now"
);
411
}
412
413
lmp.scatter_atoms(
LAMMPSObj
,
"x"
, 1, 3,
const_cast<
double
*
>
(R));
414
lmp.command(
LAMMPSObj
,
"run 1 pre no post no"
);
415
416
auto
*pe =
417
static_cast<
double
*
>
(lmp.extract_variable(
LAMMPSObj
,
"pe"
,
nullptr
));
418
*U = *pe;
419
free(pe);
420
421
auto
*fx =
422
static_cast<
double
*
>
(lmp.extract_variable(
LAMMPSObj
,
"fx"
,
"all"
));
423
auto
*fy =
424
static_cast<
double
*
>
(lmp.extract_variable(
LAMMPSObj
,
"fy"
,
"all"
));
425
auto
*fz =
426
static_cast<
double
*
>
(lmp.extract_variable(
LAMMPSObj
,
"fz"
,
"all"
));
427
428
for
(
long
i = 0; i < N; i++) {
429
F[3 * i + 0] = fx[i];
430
F[3 * i + 1] = fy[i];
431
F[3 * i + 2] = fz[i];
432
}
433
434
// Convert kCal/mol -> eV if LAMMPS is using real units
435
if
(
realunits
) {
436
constexpr
double
kcalPerEv = 23.0609;
437
*U /= kcalPerEv;
438
for
(
long
i = 0; i < 3 * N; i++) {
439
F[i] /= kcalPerEv;
440
}
441
}
442
443
free(fx);
444
free(fy);
445
free(fz);
446
}
catch
(...) {
447
fpeh.
restore_fpe
();
448
throw
;
449
}
450
fpeh.
restore_fpe
();
451
}
452
453
void
LAMMPSPot::makeNewLAMMPS
(
long
N,
const
double
*R,
const
int
*atomicNrs,
454
const
double
*box) {
455
auto
&lmp =
eonc::LammpsLoader::instance
();
456
457
numberOfAtoms
= N;
458
std::memcpy(
oldBox
, box, 9 *
sizeof
(
double
));
459
460
if
(
LAMMPSObj
!=
nullptr
) {
461
eonc::LammpsLoader::instance
().
close
(
LAMMPSObj
);
462
LAMMPSObj
=
nullptr
;
463
}
464
465
// Map atomic numbers to LAMMPS type indices (1-based)
466
std::map<int, int> type_map;
467
int
ntypes = 0;
468
for
(
long
i = 0; i < N; i++) {
469
if
(type_map.count(atomicNrs[i]) == 0) {
470
type_map.insert({atomicNrs[i], ++ntypes});
471
}
472
}
473
474
#ifdef EONMPI
475
const
char
*lmpargv[] = {
"liblammps"
,
"-log"
,
"none"
,
"-echo"
,
"log"
,
476
"-screen"
,
"none"
,
"-suffix"
,
"omp"
};
477
int
lmpargc =
sizeof
(lmpargv) /
sizeof
(
const
char
*);
478
if
(!lmp.open_mpi) {
479
throw
std::runtime_error(
480
"LAMMPS library found but lacks MPI support (lammps_open not found).\n"
481
"Install an MPI-enabled LAMMPS build."
);
482
}
483
MPI_Comm inst_comm = MPI_COMM_NULL;
484
MPI_Comm_dup(mpiComm, &inst_comm);
// private comm per per-image instance
485
LAMMPSObj
=
486
lmp.open_mpi(lmpargc,
const_cast<
char
**
>
(lmpargv), inst_comm,
nullptr
);
487
#else
488
const
char
*lmpargv[] = {
"liblammps"
,
"-log"
,
"none"
,
"-echo"
,
489
"log"
,
"-screen"
,
"none"
};
490
int
lmpargc =
sizeof
(lmpargv) /
sizeof
(
const
char
*);
491
LAMMPSObj
= lmp.open_no_mpi(lmpargc,
const_cast<
char
**
>
(lmpargv),
nullptr
);
492
#endif
493
494
if
(
lammpsThr
> 0) {
495
std::string cmd = std::format(
"package omp {} force/neigh"
,
lammpsThr
);
496
lmp.command(
LAMMPSObj
, cmd.c_str());
497
}
498
499
// Detect units from in.lammps: look for "#!units real" marker
500
realunits
=
false
;
501
if
(std::filesystem::exists(
"in.lammps"
)) {
502
std::ifstream infile(
"in.lammps"
);
503
std::string line;
504
while
(std::getline(infile, line)) {
505
if
(line ==
"#!units real"
) {
506
realunits
=
true
;
507
break
;
508
}
509
}
510
}
else
{
511
EONC_LOG_ERROR
(
"[LAMMPS] in.lammps not found in working directory"
);
512
return
;
513
}
514
515
if
(
realunits
) {
516
lmp.command(
LAMMPSObj
,
"units real"
);
517
}
else
{
518
lmp.command(
LAMMPSObj
,
"units metal"
);
519
}
520
521
lmp.command(
LAMMPSObj
,
"atom_style charge"
);
522
lmp.command(
LAMMPSObj
,
"atom_modify map array sort 0 0"
);
523
lmp.command(
LAMMPSObj
,
"neigh_modify delay 1"
);
524
525
// Define periodic cell (prism for non-orthorhombic)
526
std::string region_cmd =
527
std::format(
"region cell prism 0 {} 0 {} 0 {} {} {} {} units box"
, box[0],
528
box[4], box[8], box[3], box[6], box[7]);
529
lmp.command(
LAMMPSObj
, region_cmd.c_str());
530
531
std::string create_box_cmd = std::format(
"create_box {} cell"
, ntypes);
532
lmp.command(
LAMMPSObj
, create_box_cmd.c_str());
533
534
// Initialize atoms
535
for
(
long
i = 0; i < N; i++) {
536
std::string atom_cmd =
537
std::format(
"create_atoms {} single {} {} {} units box"
,
538
type_map[atomicNrs[i]], 0.0, 0.0, 0.0);
539
lmp.command(
LAMMPSObj
, atom_cmd.c_str());
540
}
541
542
lmp.command(
LAMMPSObj
,
"mass * 1.0"
);
543
544
// Load user LAMMPS input script
545
lmp.file(
LAMMPSObj
,
"in.lammps"
);
546
547
// Define variables for force/energy extraction
548
lmp.command(
LAMMPSObj
,
"variable fx atom fx"
);
549
lmp.command(
LAMMPSObj
,
"variable fy atom fy"
);
550
lmp.command(
LAMMPSObj
,
"variable fz atom fz"
);
551
lmp.command(
LAMMPSObj
,
"variable pe equal pe"
);
552
}
EonLogger.h
EONC_LOG_ERROR
#define EONC_LOG_ERROR(...)
Definition
EonLogger.h:262
EONC_LOG_WARNING
#define EONC_LOG_WARNING(...)
Definition
EonLogger.h:256
LAMMPSPot.h
LammpsLoader.h
LAMMPSPot::oldBox
double oldBox[9]
Definition
LAMMPSPot.h:39
LAMMPSPot::reqFd
int reqFd
Definition
LAMMPSPot.h:72
LAMMPSPot::workerPid
int workerPid
Definition
LAMMPSPot.h:71
LAMMPSPot::makeNewLAMMPS
void makeNewLAMMPS(long N, const double *R, const int *atomicNrs, const double *box)
Definition
LAMMPSPot.cpp:453
LAMMPSPot::LAMMPSPot
LAMMPSPot(const Parameters &p)
Definition
LAMMPSPot.cpp:40
LAMMPSPot::lammpsThr
int lammpsThr
Definition
LAMMPSPot.h:34
LAMMPSPot::~LAMMPSPot
~LAMMPSPot()
Definition
LAMMPSPot.cpp:61
LAMMPSPot::workerSpawned
bool workerSpawned
Definition
LAMMPSPot.h:74
LAMMPSPot::cleanMemory
void cleanMemory()
Definition
LAMMPSPot.cpp:63
LAMMPSPot::workerRespawnsLeft
int workerRespawnsLeft
Definition
LAMMPSPot.h:61
LAMMPSPot::realunits
bool realunits
Definition
LAMMPSPot.h:43
LAMMPSPot::stopWorker
void stopWorker()
Definition
LAMMPSPot.cpp:232
LAMMPSPot::LAMMPSObj
void * LAMMPSObj
Definition
LAMMPSPot.h:40
LAMMPSPot::ensureWorker
void ensureWorker()
Definition
LAMMPSPot.cpp:140
LAMMPSPot::runWorkerLoop
void runWorkerLoop()
Definition
LAMMPSPot.cpp:192
LAMMPSPot::numberOfAtoms
long numberOfAtoms
Definition
LAMMPSPot.h:38
LAMMPSPot::force
void force(long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box) override
Definition
LAMMPSPot.cpp:273
LAMMPSPot::forceLocal
void forceLocal(long N, const double *R, const int *atomicNrs, double *F, double *U, const double *box)
Definition
LAMMPSPot.cpp:388
LAMMPSPot::workerMutex
std::mutex workerMutex
Definition
LAMMPSPot.h:70
LAMMPSPot::resFd
int resFd
Definition
LAMMPSPot.h:73
eonc::FPEHandler
Definition
fpe_handler.h:25
eonc::FPEHandler::restore_fpe
void restore_fpe()
Definition
fpe_handler.cpp:251
eonc::FPEHandler::eat_fpe
void eat_fpe()
Definition
fpe_handler.cpp:246
eonc::LammpsLoader::require_loaded
void require_loaded()
Load on first use, then throw if liblammps is not available.
Definition
LammpsLoader.cpp:124
eonc::LammpsLoader::close
close_fn close
Definition
LammpsLoader.h:52
eonc::LammpsLoader::instance
static LammpsLoader & instance()
Thread-safe singleton accessor (Meyer's pattern). Does not dlopen.
Definition
LammpsLoader.cpp:79
eonc::Parameters
Definition
Parameters.h:28
eonc::Potential::Potential
Potential(PotType a_ptype)
Definition
Potential.h:35
fpe_handler.h
eonc::disableFPE
void disableFPE()
Definition
fpe_handler.cpp:229
client
potentials
LAMMPS
LAMMPSPot.cpp
Generated by
1.17.0
Generated by
Doxygen 1.17.0
Analytics by
Antics
provided by
TurtleTech ehf