Loading...
Searching...
No Matches
ExtPot Class Reference

#include <ExtPot.h>

Inheritance diagram for ExtPot:

Public Member Functions

 ExtPot (const Parameters &p)
 ~ExtPot ()
void cleanMemory (void)
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
 One instance owns one exchange directory, so two threads in force() on it write the same structure file and read the same result.
bool needsPerImageInstance () const noexcept override
 The external program runs as a subprocess and each instance runs it in a directory of its own, so separate instances are independent.
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.

Private Member Functions

void passToSystem (long N, const double *R, const int *atomicNrs, const double *box)
void recieveFromSystem (long N, double *F, double *U)
void prepareExchangeDir ()

Private Attributes

std::string eon_extpot_path
std::filesystem::path exchangeDir
bool retainExchangeDir {false}

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 19 of file ExtPot.h.

Constructor & Destructor Documentation

◆ ExtPot()

ExtPot::ExtPot ( const Parameters & p)

Definition at line 120 of file ExtPot.cpp.

121 : Potential(p),
122 eon_extpot_path{resolveCommand(p.potential_options.extPotPath)} {}
std::string eon_extpot_path
Definition ExtPot.h:45
struct eonc::Parameters::potential_options_t potential_options
Potential(PotType a_ptype)
Definition Potential.h:35

◆ ~ExtPot()

ExtPot::~ExtPot ( )

Definition at line 136 of file ExtPot.cpp.

136{ cleanMemory(); }
void cleanMemory(void)
Definition ExtPot.cpp:124

Member Function Documentation

◆ cleanMemory()

void ExtPot::cleanMemory ( void )

Definition at line 124 of file ExtPot.cpp.

124 {
125 if (exchangeDir.empty() || retainExchangeDir) {
126 return;
127 }
128 std::error_code ec;
129 std::filesystem::remove(exchangeDir / kToExtPot, ec);
130 std::filesystem::remove(exchangeDir / kFromExtPot, ec);
131 // Removes the directory only when it is empty, so whatever else the
132 // external program wrote there stays.
133 std::filesystem::remove(exchangeDir, ec);
134}
bool retainExchangeDir
Definition ExtPot.h:52
std::filesystem::path exchangeDir
Definition ExtPot.h:49

◆ force()

void ExtPot::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 166 of file ExtPot.cpp.

167 {
168 variance = nullptr;
169 if (eon_extpot_path.empty()) {
170 throw std::runtime_error(
171 "ExtPot needs potential_options.extPotPath to name a program to run");
172 }
174 retainExchangeDir = true;
175 passToSystem(N, R, atomicNrs, box);
176 std::error_code ec;
177 const std::filesystem::path runDir = std::filesystem::current_path(ec);
178 eonc::pot::runOrThrow(composeCommand(exchangeDir.string(),
179 ec ? std::string{} : runDir.string(),
181 recieveFromSystem(N, F, U);
182 retainExchangeDir = false;
183 return;
184}
void recieveFromSystem(long N, double *F, double *U)
Definition ExtPot.cpp:215
void prepareExchangeDir()
Definition ExtPot.cpp:138
void passToSystem(long N, const double *R, const int *atomicNrs, const double *box)
Definition ExtPot.cpp:186
void runOrThrow(const std::string &command)
Run a shell command, throwing when it does not succeed.

◆ isThreadSafe()

bool ExtPot::isThreadSafe ( ) const
inlinenodiscardoverridevirtualnoexcept

One instance owns one exchange directory, so two threads in force() on it write the same structure file and read the same result.

Reimplemented from eonc::Potential.

Definition at line 29 of file ExtPot.h.

29{ return false; }

◆ needsPerImageInstance()

bool ExtPot::needsPerImageInstance ( ) const
inlinenodiscardoverridevirtualnoexcept

The external program runs as a subprocess and each instance runs it in a directory of its own, so separate instances are independent.

Reimplemented from eonc::Potential.

Definition at line 32 of file ExtPot.h.

32 {
33 return true;
34 }

◆ passToSystem()

void ExtPot::passToSystem ( long N,
const double * R,
const int * atomicNrs,
const double * box )
private

Definition at line 186 of file ExtPot.cpp.

189{
190 const std::filesystem::path toExtPot = exchangeDir / kToExtPot;
191 std::ofstream out(toExtPot, std::ios::trunc);
192 if (!out) {
193 throw std::runtime_error(
194 std::format("Could not open {} for writing", toExtPot.string()));
195 }
196
197 for (int i = 0; i < 3; i++) {
198 out << std::format("{:.19f}\t{:.19f}\t{:.19f}\n", box[i * 3 + 0],
199 box[i * 3 + 1], box[i * 3 + 2]);
200 }
201
202 for (long i = 0; i < N; i++) {
203 out << std::format("{}\t{:.19f}\t{:.19f}\t{:.19f}\n", atomicNrs[i],
204 R[i * 3 + 0], R[i * 3 + 1], R[i * 3 + 2]);
205 }
206
207 out.close();
208 if (!out) {
209 throw std::runtime_error(
210 std::format("Could not write the structure to {}", toExtPot.string()));
211 }
212 return;
213}

◆ prepareExchangeDir()

void ExtPot::prepareExchangeDir ( )
private

Definition at line 138 of file ExtPot.cpp.

138 {
139 std::error_code ec;
140 if (exchangeDir.empty()) {
141 // One directory per potential object. A client started alongside this
142 // one carries a different process id, and a second potential in this
143 // process a different index, so no two of them name the same file.
144 static std::atomic<long> instanceCount{0};
145 const std::filesystem::path named{
146 std::format("extpot_{}_{}", processId(), instanceCount.fetch_add(1))};
147 exchangeDir = std::filesystem::absolute(named, ec);
148 if (ec) {
149 exchangeDir.clear();
150 throw std::runtime_error(std::format("Could not resolve {}: {}",
151 named.string(), ec.message()));
152 }
153 }
154 std::filesystem::create_directory(exchangeDir, ec);
155 if (ec) {
156 throw std::runtime_error(std::format("Could not create {} to run {} in: {}",
158 ec.message()));
159 }
160 // A result left by an earlier call, or by a client that died holding this
161 // process id, is read as this call's forces when the external program
162 // writes nothing.
163 std::filesystem::remove(exchangeDir / kFromExtPot, ec);
164}

◆ recieveFromSystem()

void ExtPot::recieveFromSystem ( long N,
double * F,
double * U )
private

Create the directory the external command runs in and clear any exchange file left in it.

Definition at line 215 of file ExtPot.cpp.

218{
219 const std::filesystem::path fromExtPot = exchangeDir / kFromExtPot;
220 std::ifstream in(fromExtPot);
221 if (!in) {
222 throw std::runtime_error(
223 std::format("Could not open {}; the external program left no result",
224 fromExtPot.string()));
225 }
226
227 if (!(in >> *U)) {
228 throw std::runtime_error(
229 std::format("Could not read the energy from {}", fromExtPot.string()));
230 }
231
232 for (long i = 0; i < N; i++) {
233 if (!(in >> F[i * 3 + 0] >> F[i * 3 + 1] >> F[i * 3 + 2])) {
234 throw std::runtime_error(
235 std::format("{} holds forces for {} atoms, expected {}",
236 fromExtPot.string(), i, N));
237 }
238 }
239 return;
240}

Member Data Documentation

◆ eon_extpot_path

std::string ExtPot::eon_extpot_path
private

The directory this potential runs the external command in. The exchange files keep their documented names and live here, so two clients started in one directory cannot read each other's numbers.

Definition at line 45 of file ExtPot.h.

◆ exchangeDir

std::filesystem::path ExtPot::exchangeDir
private

Set while a call is in flight, so a call that fails leaves its exchange files in place to be looked at.

Definition at line 49 of file ExtPot.h.

◆ retainExchangeDir

bool ExtPot::retainExchangeDir {false}
private

Definition at line 52 of file ExtPot.h.

52{false};

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