Loading...
Searching...
No Matches
AMS_IO.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
14#include "eon/Parameters.h"
16
17#include <cstddef>
18#include <cstdint>
19#include <cstring>
20#include <format>
21#include <fstream>
22#include <iostream>
23#include <iterator>
24#include <readcon-core.hpp>
25#include <stdexcept>
26#include <string>
27#ifndef _WIN32
28#include <sys/stat.h>
29#include <unistd.h>
30#endif
31
32namespace {
33
34// The driver script and its output, both relative to the working directory.
35constexpr const char *kRunScript = "run_AMS_IO.sh";
36constexpr const char *kOutputFile = "ams_output";
37// Truncating rather than appending keeps the previous call's block out of the
38// parse, so a failed run cannot hand back stale forces.
39constexpr const char *kRunCommand = "./run_AMS_IO.sh > ams_output";
40
41// Lines that precede the two blocks of interest in the AMS output.
42constexpr const char *kEnergyMarker = " CALCULATION RESULTS";
43constexpr const char *kGradientMarker =
44 " Index Atom d/dx d/dy d/dz";
45
46constexpr double kHartreeToEv = 27.2114;
47constexpr double kHartreeBohrToEvAngstrom = 51.4220862;
48
49} // namespace
50
52 : eonc::Potential(eonc::PotType::AMS_IO, p) {
56 xc = p.ams_options().xc;
57 return;
58}
59
60void AMS_IO::cleanMemory(void) { return; }
61
63
64namespace {
65
66std::string symbol_for_z(int n) {
67 if (n <= 0) {
68 throw std::runtime_error(
69 std::format("AMS_IO knows no element symbol for atomic number {}", n));
70 }
71 return readcon::z_to_symbol(static_cast<uint64_t>(n));
72}
73} // namespace
74
75void AMS_IO::force(long N, const double *R, const int *atomicNrs, double *F,
76 double *U, double *variance, const double *box) {
77 variance = nullptr;
78 passToSystem(N, R, atomicNrs, box);
79 // Run a single point AMS_IO calculation and write the results into
80 // ams_output
81 eonc::pot::runOrThrow(kRunCommand);
82 recieveFromSystem(N, F, U);
83 return;
84}
85
86void AMS_IO::passToSystem(long N, const double *R, const int *atomicNrs,
87 const double *box)
88// Creating the standard input file that will be read by the AMS_IO driver
89{
90 std::ofstream out(kRunScript, std::ios::trunc);
91 if (!out) {
92 throw std::runtime_error(
93 std::format("Could not open {} for writing", kRunScript));
94 }
95
96 out << "#!/bin/sh\n";
97 out << "ams --delete-old-results <<eor\n";
98 out << "Task SinglePoint\n";
99 out << "System\n";
100 out << " Atoms\n";
101 for (long i = 0; i < N; i++) {
102 out << std::format(" {}\t{:.19f}\t{:.19f}\t{:.19f}\n",
103 symbol_for_z(atomicNrs[i]), R[i * 3 + 0], R[i * 3 + 1],
104 R[i * 3 + 2]);
105 }
106 out << " End\n";
107 if (!model.empty() || !forcefield.empty()) {
108 out << " Lattice\n";
109 for (int i = 0; i < 3; i++) {
110 out << std::format(" {:.19f}\t{:.19f}\t{:.19f}\n", box[i * 3 + 0],
111 box[i * 3 + 1], box[i * 3 + 2]);
112 }
113 out << " End\n";
114 }
115 out << "End\n";
116 out << std::format("Engine {}\n", engine);
117 if (!forcefield.empty()) {
118 out << std::format(" Forcefield {}\n", forcefield);
119 }
120 if (!model.empty()) {
121 out << std::format(" Model {}\n", model);
122 }
123 if (!xc.empty()) {
124 out << std::format("xc {}\n", xc);
125 // basis set not specified (default = DZ)
126 out << std::format(" hybrid {}\n", xc);
127 out << "end\n";
128 }
129 out << "EndEngine\n";
130 out << "Properties\n";
131 out << " Gradients\n";
132 out << "End\n";
133 out << "eor";
134
135 out.close();
136 if (!out) {
137 throw std::runtime_error(
138 std::format("Could not write the AMS input to {}", kRunScript));
139 }
140
141#ifndef _WIN32
142 if (chmod(kRunScript, S_IRWXU) != 0) {
143 throw std::runtime_error(
144 std::format("Could not make {} executable", kRunScript));
145 }
146#endif
147 return;
148}
149
150void AMS_IO::recieveFromSystem(long N, double *F, double *U) {
151 std::ifstream in(kOutputFile);
152 if (!in) {
153 throw std::runtime_error(
154 std::format("Could not open {}; AMS left no output", kOutputFile));
155 }
156
157 bool haveEnergy = false;
158 bool haveGradients = false;
159 std::string line;
160
161 while (std::getline(in, line)) {
162
163 if (line == kEnergyMarker) { // Finding the Energy in the output file
164 std::string junk;
165 if (!(in >> junk >> junk >> junk >> *U)) {
166 throw std::runtime_error(
167 std::format("Could not read the energy following \"{}\" in {}",
168 kEnergyMarker, kOutputFile));
169 }
170 *U = *U * kHartreeToEv; // Energy in hartree to eV
171 haveEnergy = true;
172 }
173
174 if (line == kGradientMarker) { // Finding the forces
175 double index;
176 std::string symbol;
177 for (long i = 0; i < N; i++) {
178 if (!(in >> index >> symbol >> F[i * 3 + 0] >> F[i * 3 + 1] >>
179 F[i * 3 + 2])) {
180 throw std::runtime_error(
181 std::format("{} holds gradients for {} atoms, expected {}",
182 kOutputFile, i, N));
183 }
184 // AMS_IO gives gradients, not forces, hence the change.
185 F[i * 3 + 0] = -F[i * 3 + 0];
186 F[i * 3 + 1] = -F[i * 3 + 1];
187 F[i * 3 + 2] = -F[i * 3 + 2];
188 }
189 haveGradients = true;
190 }
191 }
192
193 if (!haveEnergy || !haveGradients) {
194 throw std::runtime_error(std::format(
195 "{} holds no {}", kOutputFile,
196 !haveEnergy
197 ? (!haveGradients ? "energy and no gradient block" : "energy")
198 : "gradient block"));
199 }
200
201 for (long i = 0; i < 3 * N; i++) {
202 F[i] = F[i] * kHartreeBohrToEvAngstrom; // Forces from hartree/bohr to
203 // eV/Angstrom
204 }
205 return;
206}
~AMS_IO()
Definition AMS_IO.cpp:62
std::string forcefield
Definition AMS_IO.h:37
std::string model
Definition AMS_IO.h:36
std::string engine
Definition AMS_IO.h:35
AMS_IO(const eonc::Parameters &p)
Definition AMS_IO.cpp:51
void force(long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box)
Definition AMS_IO.cpp:75
void recieveFromSystem(long N, double *F, double *U)
Definition AMS_IO.cpp:150
void cleanMemory(void)
Definition AMS_IO.cpp:60
std::string xc
Definition AMS_IO.h:38
void passToSystem(long N, const double *R, const int *atomicNrs, const double *box)
Definition AMS_IO.cpp:86
const ams_options_t & ams_options() const
Potential(PotType a_ptype)
Production default: construction-scope registry, else PotRegistry::get().
void runOrThrow(const std::string &command)
Run a shell command, throwing when it does not succeed.
RAII resource manager for the ARTn C library with global synchronization.