23#include <system_error>
26#ifndef WIN32_LEAN_AND_MEAN
27#define WIN32_LEAN_AND_MEAN
43constexpr const char *kToExtPot =
"from_eon_to_extpot";
44constexpr const char *kFromExtPot =
"from_extpot_to_eon";
48constexpr const char *kRunDirVariable =
"EON_EXTPOT_RUN_DIR";
52 return static_cast<long>(_getpid());
54 return static_cast<long>(getpid());
63std::string windowsPythonCommand() {
66 SearchPathA(
nullptr,
"python.exe",
nullptr, MAX_PATH, buf,
nullptr);
67 if (n > 0 && n < MAX_PATH) {
80std::string composeCommand(
const std::string &workDir,
81 const std::string &runDir,
82 const std::string &command) {
84 const std::string quotedCommand =
87 return std::format(
"cd /d {} && set \"{}={}\" && {}",
92 return std::format(
"cd {} && export {}={} && {}",
105std::string resolveCommand(
const std::string &command) {
107 const std::filesystem::path named{command};
108 if (!std::filesystem::is_regular_file(named, ec) || ec) {
111 const std::filesystem::path resolved = std::filesystem::absolute(named, ec);
115 return resolved.string();
129 std::filesystem::remove(
exchangeDir / kToExtPot, ec);
130 std::filesystem::remove(
exchangeDir / kFromExtPot, ec);
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);
150 throw std::runtime_error(std::format(
"Could not resolve {}: {}",
151 named.string(), ec.message()));
154 std::filesystem::create_directory(
exchangeDir, ec);
156 throw std::runtime_error(std::format(
"Could not create {} to run {} in: {}",
163 std::filesystem::remove(
exchangeDir / kFromExtPot, ec);
167 double *U,
double *variance,
const double *box) {
170 throw std::runtime_error(
171 "ExtPot needs potential_options.extPotPath to name a program to run");
177 const std::filesystem::path runDir = std::filesystem::current_path(ec);
179 ec ? std::string{} : runDir.string(),
190 const std::filesystem::path toExtPot =
exchangeDir / kToExtPot;
191 std::ofstream out(toExtPot, std::ios::trunc);
193 throw std::runtime_error(
194 std::format(
"Could not open {} for writing", toExtPot.string()));
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]);
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]);
209 throw std::runtime_error(
210 std::format(
"Could not write the structure to {}", toExtPot.string()));
219 const std::filesystem::path fromExtPot =
exchangeDir / kFromExtPot;
220 std::ifstream in(fromExtPot);
222 throw std::runtime_error(
223 std::format(
"Could not open {}; the external program left no result",
224 fromExtPot.string()));
228 throw std::runtime_error(
229 std::format(
"Could not read the energy from {}", fromExtPot.string()));
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));
void recieveFromSystem(long N, double *F, double *U)
void prepareExchangeDir()
ExtPot(const Parameters &p)
std::string eon_extpot_path
std::filesystem::path exchangeDir
void passToSystem(long N, const double *R, const int *atomicNrs, const double *box)
void force(long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box) override
Potential(PotType a_ptype)
void runOrThrow(const std::string &command)
Run a shell command, throwing when it does not succeed.
std::string shellQuote(const std::string &text)
Wrap a path for the shell system() hands the command to, so spaces in it survive.
std::string wrapResolvedProgram(const std::string &command, const std::string &python)
Quote a resolved program path, and on Windows prefix a script so cmd.exe can start it.