176 {
177 std::ifstream in(kOutputFile);
178 if (!in) {
179 throw std::runtime_error(
180 std::format("Could not open {}; AMS left no output", kOutputFile));
181 }
182
183 bool haveEnergy = false;
184 bool haveGradients = false;
185 std::string line;
186
187 while (std::getline(in, line)) {
188
189 if (line == kEnergyMarker) {
190 std::string junk;
191 if (!(in >> junk >> junk >> junk >> *U)) {
192 throw std::runtime_error(
193 std::format("Could not read the energy following \"{}\" in {}",
194 kEnergyMarker, kOutputFile));
195 }
196 *U = *U * kHartreeToEv;
197 haveEnergy = true;
198 }
199
200 if (line == kGradientMarker) {
201 double index;
202 std::string symbol;
203 for (long i = 0; i < N; i++) {
204 if (!(in >> index >> symbol >> F[i * 3 + 0] >> F[i * 3 + 1] >>
205 F[i * 3 + 2])) {
206 throw std::runtime_error(
207 std::format("{} holds gradients for {} atoms, expected {}",
208 kOutputFile, i, N));
209 }
210
211 F[i * 3 + 0] = -F[i * 3 + 0];
212 F[i * 3 + 1] = -F[i * 3 + 1];
213 F[i * 3 + 2] = -F[i * 3 + 2];
214 }
215 haveGradients = true;
216 }
217 }
218
219 if (!haveEnergy || !haveGradients) {
220 throw std::runtime_error(std::format(
221 "{} holds no {}", kOutputFile,
222 !haveEnergy
223 ? (!haveGradients ? "energy and no gradient block" : "energy")
224 : "gradient block"));
225 }
226
227 for (long i = 0; i < 3 * N; i++) {
228 F[i] = F[i] * kHartreeBohrToEvAngstrom;
229
230 }
231 return;
232}