Loading...
Searching...
No Matches
VASP Class Reference

#include <VASP.h>

Inheritance diagram for VASP:

Public Member Functions

 VASP (const Parameters &p)
 ~VASP ()
void initialize ()
void cleanMemory (void)
void force (long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box)
bool isThreadSafe () const noexcept override
 force() writes POSCAR, signals through NEWCAR and waits on FU, all at fixed names in the working directory, so two threads in it swap results.
bool needsPerImageInstance () const noexcept override
 Every instance drives the one VASP process named by the static vaspPID through the one set of files, so a second instance buys no parallelism.
Public Member Functions inherited from eonc::Potential
 Potential (PotType a_ptype)
 Potential (PotType a_ptype, const Parameters &)
 Potential (const Parameters &a_params)
virtual ~Potential ()
std::tuple< double, AtomMatrixget_ef (const AtomMatrix &pos, const VectorXi &atmnrs, const Matrix3d &box)
PotType getType () const
virtual bool isSurrogate () const noexcept
 Whether this is a surrogate (GP) potential.
virtual bool requiresIsolatedMoleculeLayout () const noexcept
 True for molecular QM / non-PBC backends (NWChem socket, ASE ORCA/NWChem, …).
virtual bool isSharedInstanceThreadSafe () const noexcept
 Conservative gate for sharing one Potential instance across threads.
virtual bool supportsBatchEvaluation () const noexcept
 Whether this potential supports batched evaluation of N systems in a single call.
virtual void forceBatch (long nSystems, long nAtoms, const double *const *positions, const int *const *atomicNrs, double *const *forces, double *energies, double *variances, const double *const *boxes)
 Evaluate forces for N systems in a single call.

Static Public Member Functions

static void removeStaleFiles ()

Private Member Functions

void writePOSCAR (long N, const double *R, const int *atomicNrs, const double *box)
void readFU (long N, double *F, double *U)
void spawnVASP ()
bool vaspRunning ()

Static Private Member Functions

static void clearHandshakeFiles ()

Static Private Attributes

static bool firstRun = true
static long vaspRunCount = 0
static pid_t vaspPID = 0

Additional Inherited Members

Public Attributes inherited from eonc::Potential
std::atomic< size_t > forceCallCounter
Protected Attributes inherited from eonc::Potential
PotType ptype

Detailed Description

Definition at line 16 of file VASP.h.

Constructor & Destructor Documentation

◆ VASP()

VASP::VASP ( const Parameters & p)
inline

Definition at line 19 of file VASP.h.

20 : Potential(p) {
22 }
static long vaspRunCount
Definition VASP.h:57
Potential(PotType a_ptype)
Definition Potential.h:35

◆ ~VASP()

VASP::~VASP ( )
inline

Definition at line 23 of file VASP.h.

23{ cleanMemory(); }
void cleanMemory(void)
Definition VASP.cpp:128

Member Function Documentation

◆ cleanMemory()

void VASP::cleanMemory ( void )

Definition at line 128 of file VASP.cpp.

128 {
129 vaspRunCount--;
130 if (vaspRunCount < 1) {
131 // Runs from a destructor, so it reports rather than throws.
132 std::ofstream stopcar(kStopCarFile, std::ios::trunc);
133 if (!stopcar) {
134 EONC_LOG_WARNING("Could not open {} to stop VASP", kStopCarFile);
135 return;
136 }
137 stopcar << "LABORT = .TRUE.\n";
138 stopcar.close();
139 if (!stopcar) {
140 EONC_LOG_WARNING("Could not write {} to stop VASP", kStopCarFile);
141 }
142 }
143 return;
144}
#define EONC_LOG_WARNING(...)
Definition EonLogger.h:256

◆ clearHandshakeFiles()

void VASP::clearHandshakeFiles ( )
staticprivate

Definition at line 104 of file VASP.cpp.

104 {
105 for (const char *name : kHandshakeFiles) {
106 std::error_code ec;
107 if (std::filesystem::remove(name, ec)) {
108 EONC_LOG_INFO("VASP cleared leftover {}", name);
109 } else if (ec) {
110 EONC_LOG_WARNING("VASP could not clear leftover {}: {}", name,
111 ec.message());
112 }
113 }
114}
#define EONC_LOG_INFO(...)
Definition EonLogger.h:250

◆ force()

void VASP::force ( long N,
const double * R,
const int * atomicNrs,
double * F,
double * U,
double * variance,
const double * box )
virtual

Implements eonc::Potential.

Definition at line 215 of file VASP.cpp.

216 {
217 variance = nullptr;
218 writePOSCAR(N, R, atomicNrs, box);
219
220 if (!vaspRunning()) {
221 spawnVASP();
222 }
223
224 // access() succeeds the moment VASP creates FU, not when it finishes
225 // writing it, so this can observe a partial file. readFU treats a short
226 // read as an error rather than absorbing it, which turns the race into a
227 // failure instead of wrong forces. Closing it properly needs a completion
228 // signal from runvasp.sh, such as writing to a temporary name and renaming
229 // it once the write completes.
230 while (access(kForceFile, F_OK) == -1) {
231 sleep(1);
232 vaspRunning();
233 }
234 readFU(N, F, U);
235
236 std::error_code ec;
237 if (!std::filesystem::remove(kForceFile, ec) || ec) {
238 // Leaving it behind means the next call reads this call's numbers.
239 throw std::runtime_error(std::format("Could not remove {}: {}", kForceFile,
240 ec ? ec.message() : "already gone"));
241 }
242 vaspRunCount++;
243 return;
244}
void spawnVASP()
Definition VASP.cpp:146
void writePOSCAR(long N, const double *R, const int *atomicNrs, const double *box)
Definition VASP.cpp:246
void readFU(long N, double *F, double *U)
Definition VASP.cpp:306
bool vaspRunning()
Definition VASP.cpp:197

◆ initialize()

void VASP::initialize ( )
inline

Definition at line 24 of file VASP.h.

24{};

◆ isThreadSafe()

bool VASP::isThreadSafe ( ) const
inlinenodiscardoverridevirtualnoexcept

force() writes POSCAR, signals through NEWCAR and waits on FU, all at fixed names in the working directory, so two threads in it swap results.

Reimplemented from eonc::Potential.

Definition at line 30 of file VASP.h.

30{ return false; }

◆ needsPerImageInstance()

bool VASP::needsPerImageInstance ( ) const
inlinenodiscardoverridevirtualnoexcept

Every instance drives the one VASP process named by the static vaspPID through the one set of files, so a second instance buys no parallelism.

Delete the results and restart files VASP writes into the working directory, so a calculation starts from an empty one.

Destructive, and nothing in the client calls it: a caller invokes it when it means to discard an earlier calculation's output. A caller that means to restart from WAVECAR or CHGCAR must not, and neither must one that wants the earlier OUTCAR. The examples/akmc-vasp-slurm scripts do the same removals in shell, at the point where the user asks for them.

Reimplemented from eonc::Potential.

Definition at line 33 of file VASP.h.

◆ readFU()

void VASP::readFU ( long N,
double * F,
double * U )
private

Definition at line 306 of file VASP.cpp.

306 {
307 std::ifstream fu(kForceFile);
308 if (!fu) {
309 throw std::runtime_error(
310 std::format("Could not open {}; VASP left no result", kForceFile));
311 }
312
313 if (!(fu >> *U)) {
314 throw std::runtime_error(
315 std::format("Could not read the energy from {}", kForceFile));
316 }
317
318 for (long i = 0; i < N; i++) {
319 if (!(fu >> F[i * 3 + 0] >> F[i * 3 + 1] >> F[i * 3 + 2])) {
320 throw std::runtime_error(std::format(
321 "{} holds forces for {} atoms, expected {}", kForceFile, i, N));
322 }
323 }
324 return;
325}

◆ removeStaleFiles()

void VASP::removeStaleFiles ( )
static

Definition at line 116 of file VASP.cpp.

116 {
117 for (const char *name : kStaleFiles) {
118 std::error_code ec;
119 if (std::filesystem::remove(name, ec)) {
120 EONC_LOG_INFO("VASP removed leftover {}", name);
121 } else if (ec) {
122 EONC_LOG_WARNING("VASP could not remove leftover {}: {}", name,
123 ec.message());
124 }
125 }
126}

◆ spawnVASP()

void VASP::spawnVASP ( )
private

Definition at line 146 of file VASP.cpp.

146 {
147 // Runs once per client, since vaspPID stays set for the life of the
148 // process. The POSCAR eOn just wrote stays, and the first call writes no
149 // NEWCAR, so nothing here discards a signal this run has sent.
151
152 // execlp resolves a relative path against whatever directory the process
153 // last changed to, which under the MPI dispatcher is not necessarily the
154 // one holding the run. Resolve it in the parent, where a failure can still
155 // be reported.
156 std::error_code ec;
157 const std::filesystem::path script =
158 std::filesystem::absolute(kVaspScript, ec);
159 if (ec) {
160 throw std::runtime_error(
161 std::format("Could not resolve {}: {}", kVaspScript, ec.message()));
162 }
163 if (!std::filesystem::exists(script, ec) || ec) {
164 throw std::runtime_error(
165 std::format("{} does not exist; VASP needs it in the working directory",
166 script.string()));
167 }
168 const std::string scriptPath = script.string();
169
170 if ((vaspPID = fork()) == -1) {
171 fprintf(stderr, "error forking for vasp: %s\n", strerror(errno));
172 exit(1);
173 }
174
175 if (vaspPID) {
176 /* We are the parent */
177 setvbuf(stdout, (char *)NULL, _IONBF, 0); // non-buffered output
178 } else {
179 /* We are the child */
180 int outFd = open("vaspout", O_CREAT | O_WRONLY | O_TRUNC, 0644);
181 if (outFd == -1) {
182 fprintf(stderr, "error opening vaspout: %s\n", strerror(errno));
183 _exit(1);
184 }
185 if (dup2(outFd, 1) == -1 || dup2(outFd, 2) == -1) {
186 fprintf(stderr, "error redirecting vasp output: %s\n", strerror(errno));
187 _exit(1);
188 }
189 execl(scriptPath.c_str(), scriptPath.c_str(), (char *)NULL);
190 // Only reached when the exec failed; _exit keeps the child out of the
191 // parent's exit handlers.
192 fprintf(stderr, "error spawning vasp: %s\n", strerror(errno));
193 _exit(1);
194 }
195}
static void clearHandshakeFiles()
Definition VASP.cpp:104
static pid_t vaspPID
Definition VASP.h:58
Handle open(const char *name) noexcept
Definition DynLib.h:62

◆ vaspRunning()

bool VASP::vaspRunning ( )
private

Remove the files eOn and VASP signal each other through, so a run does not inherit the handshake of one that ended in this directory.

Definition at line 197 of file VASP.cpp.

197 {
198 pid_t pid;
199 int status;
200
201 if (vaspPID == 0) {
202 return false;
203 }
204
205 pid = waitpid(vaspPID, &status, WNOHANG);
206
207 if (pid) {
208 fprintf(stderr, "vasp died unexpectedly!\n");
209 exit(1);
210 }
211
212 return true;
213}

◆ writePOSCAR()

void VASP::writePOSCAR ( long N,
const double * R,
const int * atomicNrs,
const double * box )
private

Definition at line 246 of file VASP.cpp.

247 {
248 // Positions are scaled
249 const std::vector<SpeciesRun> runs = speciesRuns(N, atomicNrs);
250
251 std::ofstream poscar("POSCAR", std::ios::trunc);
252 if (!poscar) {
253 throw std::runtime_error("Could not open POSCAR for writing");
254 }
255
256 // header line (treated as a comment)
257 for (const auto &run : runs) {
258 poscar << std::format("{} ", run.first);
259 }
260 poscar << ": Atomic numbers\n";
261
262 // boundary box
263 poscar << "1.0\n";
264 for (int i = 0; i < 3; i++) {
265 poscar << std::format(" {:.8f}\t{:.8f}\t{:.8f}\n", box[i * 3 + 0],
266 box[i * 3 + 1], box[i * 3 + 2]);
267 }
268
269 // the number of atoms of each different atomic type
270 for (std::size_t i = 0; i < runs.size(); i++) {
271 poscar << std::format("{}{}", runs[i].second,
272 i + 1 == runs.size() ? "\n" : " ");
273 }
274
275 // coordinates for all atoms
276 poscar << "Cartesian\n";
277 for (long i = 0; i < N; i++) {
278 poscar << std::format("{:.19f}\t{:.19f}\t{:.19f}\t T T T\n", R[i * 3 + 0],
279 R[i * 3 + 1], R[i * 3 + 2]);
280 }
281
282 poscar.close();
283 if (!poscar) {
284 throw std::runtime_error("Could not write the structure to POSCAR");
285 }
286
287 if (firstRun) {
288 firstRun = false;
289 } else {
290 // An empty NEWCAR tells the running VASP that a new POSCAR is ready.
291 std::ofstream newcar(kNewCarFile, std::ios::trunc);
292 if (!newcar) {
293 throw std::runtime_error(
294 std::format("Could not open {} to signal VASP", kNewCarFile));
295 }
296 newcar.close();
297 if (!newcar) {
298 throw std::runtime_error(
299 std::format("Could not write {} to signal VASP", kNewCarFile));
300 }
301 }
302
303 return;
304}
static bool firstRun
Definition VASP.h:56

Member Data Documentation

◆ firstRun

bool VASP::firstRun = true
staticprivate

Definition at line 56 of file VASP.h.

◆ vaspPID

pid_t VASP::vaspPID = 0
staticprivate

Definition at line 58 of file VASP.h.

◆ vaspRunCount

long VASP::vaspRunCount = 0
staticprivate

Definition at line 57 of file VASP.h.


The documentation for this class was generated from the following files:
  • /home/runner/work/eOn/eOn/include/eon/potentials/VASP/VASP.h
  • /home/runner/work/eOn/eOn/client/potentials/VASP/VASP.cpp