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

#include <VASP.h>

Inheritance diagram for VASP:

Public Member Functions

 VASP (const eonc::Parameters &p)
 ~VASP ()
void initialize ()
void cleanMemory ()
void force (long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box) override
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)
 Production default: construction-scope registry, else PotRegistry::get().
 Potential (PotType a_ptype, IPotRegistry &registry)
 Test seam: injected registry, no process-default get() counters.
 Potential (PotType a_ptype, const Parameters &p)
 Potential (const Parameters &a_params)
virtual ~Potential ()
void force (std::span< const double > positions, std::span< const int > atomicNrs, std::span< double > forces, double *energy, double *variance, std::span< const double > box)
 C++ call site: size-checked view over the raw FFI force().
virtual void setFixedMask (long nAtoms, const double *isFixed)
 Optional frozen-atom mask (nAtoms*3, 1.0 = fixed).
std::tuple< double, AtomMatrix > get_ef (const AtomMatrix &pos, const VectorXi &atmnrs, const Matrix3d &box)
PotType getType () const
virtual double finiteCutoff () const noexcept
 Finite interaction range in position length units.
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 unsigned layoutFlags () const noexcept
virtual bool isSharedInstanceThreadSafe () const noexcept
 Conservative gate for sharing one Potential instance across threads.
virtual std::shared_ptr< Potential > clonePotential () const
 Independent instance that does not reload from disk.
virtual bool supportsBatchEvaluation () const noexcept
 Whether this potential supports batched evaluation of N systems in a single call.
virtual bool computesStress () const noexcept
 True when force() leaves a Cauchy stress that cauchyStress() can read until the next force() on this instance.
virtual Matrix3d cauchyStress () const
 Cauchy stress in eV/Angstrom^3.
virtual void forceBatchOwned (long nSystems, long nAtoms, const double *const *positions, const int *const *atomicNrs, double *const *forces, double *energies, double *variances, const double *const *boxes, const long *owners)
 Evaluate forces for 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)

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 Types inherited from eonc::Potential
enum class  PotLayout : unsigned { InProcess = 1u << 0 , NeedsWorkingDirectory = 1u << 1 , Subprocess = 1u << 2 }
 How the pot is executed. Combine with bitwise or. More...
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 eonc::Parameters & p)
inline

Definition at line 19 of file VASP.h.

19: eonc::Potential(p) { vaspRunCount++; }
static long vaspRunCount
Definition VASP.h:54

◆ ~VASP()

VASP::~VASP ( )
inline

Definition at line 20 of file VASP.h.

20{ cleanMemory(); }
void cleanMemory()
Definition VASP.cpp:126

Member Function Documentation

◆ cleanMemory()

void VASP::cleanMemory ( void )

Definition at line 126 of file VASP.cpp.

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

◆ clearHandshakeFiles()

void VASP::clearHandshakeFiles ( )
staticprivate

Definition at line 102 of file VASP.cpp.

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

◆ force()

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

Implements eonc::Potential.

Definition at line 219 of file VASP.cpp.

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

◆ initialize()

void VASP::initialize ( )
inline

Definition at line 21 of file VASP.h.

21{};

◆ 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 27 of file VASP.h.

27{ 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 30 of file VASP.h.

◆ readFU()

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

Definition at line 312 of file VASP.cpp.

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

◆ removeStaleFiles()

void VASP::removeStaleFiles ( )
static

Definition at line 114 of file VASP.cpp.

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

◆ spawnVASP()

void VASP::spawnVASP ( )
private

Definition at line 144 of file VASP.cpp.

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

◆ 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 // EINTR means the child is still running. Treating it as death aborts a
207 // live VASP job.
208 if (pid < 0 && errno == EINTR) {
209 return true;
210 }
211
212 if (pid != 0) {
213 throw std::runtime_error("vasp died unexpectedly");
214 }
215
216 return true;
217}

◆ writePOSCAR()

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

Definition at line 252 of file VASP.cpp.

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

Member Data Documentation

◆ firstRun

bool VASP::firstRun = true
staticprivate

Definition at line 53 of file VASP.h.

◆ vaspPID

pid_t VASP::vaspPID = 0
staticprivate

Definition at line 55 of file VASP.h.

◆ vaspRunCount

long VASP::vaspRunCount = 0
staticprivate

Definition at line 54 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