Loading...
Searching...
No Matches
HelperFunctions.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#include "eon/HelperFunctions.h"
13#include "eon/EonLogger.h"
14#include "eon/EpiCenters.h"
17#include "eon/Optimizer.h"
18#include "eon/Parameters.h"
19#include "eon/SafeMath.h"
20
21#include <cassert>
22#include <cerrno>
23#include <chrono>
24#include <cmath>
25#include <cstring>
26#include <ctime>
27#include <filesystem>
28#include <format>
29#include <fstream>
30#include <iostream>
31#include <memory>
32#include <sstream>
33#include <stdexcept>
34#include <utility>
35
36#ifndef _WIN32
37#include <sys/resource.h>
38#include <sys/time.h>
39#endif
40// Vector functions.
41// Make v1 orthogonal to v2
43 const AtomMatrix v2) {
44 return v1 - matDot(v1, v2) * eonc::safemath::safe_normalized(v2);
45}
46
47void eonc::helpers::getTime(double *real, double *user, double *sys) {
48 using namespace std::chrono;
49 auto now = steady_clock::now();
50 if (real) {
51 *real = duration<double>(now.time_since_epoch()).count();
52 }
53
54#ifdef _WIN32
55 if (user)
56 *user = 0.0;
57 if (sys)
58 *sys = 0.0;
59#else
60 struct rusage r_usage;
61 if (getrusage(RUSAGE_SELF, &r_usage) != 0) {
62 EONC_LOG_WARNING("problem getting usage info: {}", strerror(errno));
63 }
64 if (user) {
65 *user = static_cast<double>(r_usage.ru_utime.tv_sec) +
66 static_cast<double>(r_usage.ru_utime.tv_usec) / 1e6;
67 }
68 if (sys) {
69 *sys = static_cast<double>(r_usage.ru_stime.tv_sec) +
70 static_cast<double>(r_usage.ru_stime.tv_usec) / 1e6;
71 }
72#endif
73}
74
75bool eonc::helpers::existsFile(std::string filename) {
76 return std::filesystem::exists(filename);
77}
78
79std::optional<std::string>
80eonc::helpers::enterJobDirectory(std::string_view jobPath) {
81 try {
82 std::filesystem::current_path(std::filesystem::path{jobPath});
83 } catch (const std::filesystem::filesystem_error &err) {
84 return std::string{err.what()};
85 }
86 return std::nullopt;
87}
88
89bool eonc::helpers::stageReturnLog(std::string_view logHome,
90 std::string_view name) {
91 namespace fs = std::filesystem;
92 if (name.empty() || name == "." || name == ".." ||
93 name.find('/') != std::string_view::npos ||
94 name.find('\\') != std::string_view::npos) {
95 return false;
96 }
97 const fs::path dest{std::string{name}};
98 std::error_code ec;
99 const bool destFile = fs::is_regular_file(dest, ec);
100 if (logHome.empty()) {
101 return destFile;
102 }
103 const fs::path src = fs::path{std::string{logHome}} / dest.filename();
104 ec.clear();
105 if (!fs::is_regular_file(src, ec)) {
106 return destFile;
107 }
108 ec.clear();
109 if (destFile && fs::equivalent(src, dest, ec)) {
110 return true;
111 }
112 ec.clear();
113 fs::copy_file(src, dest, fs::copy_options::overwrite_existing, ec);
114 if (ec) {
115 EONC_LOG_ERROR("stageReturnLog: cannot copy {} to {}: {}", src.string(),
116 dest.string(), ec.message());
117 return fs::is_regular_file(dest);
118 }
119 return true;
120}
121
122std::string eonc::helpers::getRelevantFile(std::string filename) {
123 const auto dot = filename.rfind('.');
124 const std::string prefix =
125 (dot == std::string::npos) ? filename : filename.substr(0, dot);
126 const std::string postfix =
127 (dot == std::string::npos) ? std::string{} : filename.substr(dot);
128 std::string filenameRelevant = prefix + "_cp" + postfix;
129 if (existsFile(filenameRelevant)) {
130 return filenameRelevant;
131 }
132 filenameRelevant = prefix + "_in" + postfix;
133 if (existsFile(filenameRelevant)) {
134 return filenameRelevant;
135 }
136 return filename;
137}
138
139VectorXd eonc::helpers::loadMasses(std::string filename, int nAtoms) {
140 std::ifstream massFile(filename.c_str());
141 if (!massFile.is_open()) {
142 EONC_LOG_CRITICAL("File {} was not found", filename);
143 throw std::runtime_error(std::format("cannot open {}", filename));
144 }
145
146 VectorXd masses(nAtoms);
147 for (int i = 0; i < nAtoms; i++) {
148 double mass;
149 if (!(massFile >> mass)) {
150 EONC_LOG_CRITICAL("Error reading {}", filename);
151 throw std::runtime_error(
152 std::format("{} ended after {} of {} masses", filename, i, nAtoms));
153 }
154 masses(i) = mass;
155 }
156
157 massFile.close();
158
159 return masses;
160}
161
162AtomMatrix eonc::helpers::loadMode(FILE *modeFile, int nAtoms) {
163 AtomMatrix mode;
164 mode.resize(nAtoms, 3);
165 mode.setZero();
166 for (int i = 0; i < nAtoms; i++) {
167 if (fscanf(modeFile, "%lf %lf %lf", &mode(i, 0), &mode(i, 1),
168 &mode(i, 2)) != 3) {
169 EONC_LOG_CRITICAL("Mode file ended after {} of {} atoms", i, nAtoms);
170 throw std::runtime_error(
171 std::format("mode file ended after {} of {} atoms", i, nAtoms));
172 }
173 }
174 return mode;
175}
176
177AtomMatrix eonc::helpers::loadMode(std::string filename, int nAtoms) {
178 // Unique FILE* with RAII cleanup
179 auto closer = [](FILE *f) {
180 if (f)
181 std::fclose(f);
182 };
183 std::unique_ptr<FILE, decltype(closer)> modeFile(
184 std::fopen(filename.c_str(), "rb"), closer);
185 if (!modeFile) {
186 EONC_LOG_CRITICAL("File {} was not found", filename);
187 throw std::runtime_error(std::format("cannot open {}", filename));
188 }
189 return loadMode(modeFile.get(), nAtoms);
190}
191
193 Matter &target, const Matter &initial, const std::string &displacementPath,
194 const std::string &modePath, double scale) {
195 if (eonc::io::io_ok(target.con2matter(displacementPath))) {
196 if (target.numberOfAtoms() != initial.numberOfAtoms()) {
197 EONC_LOG_ERROR("{} holds {} atoms, the initial structure has {}",
198 displacementPath, target.numberOfAtoms(),
199 initial.numberOfAtoms());
200 return false;
201 }
202 // displacement.con may carry stale fixed-atom coordinates from a prior run.
203 // It also usually has sequential column-5 ids; keep the reactant's.
204 const AtomMatrix &initPos = initial.getPositions();
205 AtomMatrix pos = target.getPositionsCopy();
206 const long n = initial.numberOfAtoms();
207 std::vector<long> fileMap(static_cast<size_t>(n));
208 for (long i = 0; i < n; i++) {
209 if (initial.getFixed(i)) {
210 pos.row(i) = initPos.row(i);
211 }
212 target.setAtomIndex(i, initial.getAtomIndex(i));
213 fileMap[static_cast<size_t>(i)] = initial.mapFileRow(i);
214 }
215 target.setFileToMatter(std::move(fileMap));
216 target.setPositions(pos);
217 return true;
218 }
219 if (!existsFile(modePath)) {
220 return false;
221 }
222 AtomMatrix mode =
223 loadMode(modePath, static_cast<int>(initial.numberOfAtoms()));
224 const double norm = mode.norm();
225 if (!(norm > 0.0)) {
226 return false;
227 }
228 mode *= (scale / norm);
229 target = initial;
230 AtomMatrix pos = initial.getPositionsCopy();
231 pos += mode;
232 const AtomMatrix &initPos = initial.getPositions();
233 const long n = initial.numberOfAtoms();
234 for (long i = 0; i < n; i++) {
235 if (initial.getFixed(i)) {
236 pos.row(i) = initPos.row(i);
237 }
238 }
239 target.setPositions(pos);
240 EONC_LOG_INFO("Synthesized displacement from pos.con + scale {:.6g} * unit "
241 "mode in {} (missing {})",
242 scale, modePath, displacementPath);
243 return true;
244}
245
247 const Matter &initial,
248 const Parameters &params,
249 AtomMatrix *modeOut) {
250 using namespace eonc::EpiCenters;
251 const auto &opt = params.saddle_search_options();
252 const std::string &dtype = opt.displace_type;
253 if (dtype == DISP_LOAD) {
254 return false;
255 }
256
257 long epicenter = -1;
258 const double cutoff = params.structure_comparison_options().neighbor_cutoff;
259 if (dtype == DISP_LISTED_ATOMS) {
260 epicenter = listedAtomEpiCenter(&initial, opt.displace_atom_list);
261 } else if (dtype == DISP_RANDOM) {
262 epicenter = randomFreeAtomEpiCenter(&initial);
263 } else if (dtype == DISP_LAST_ATOM) {
264 epicenter = lastAtom(&initial);
265 } else if (dtype == DISP_MIN_COORDINATED) {
266 epicenter = minCoordinatedEpiCenter(&initial, cutoff);
267 } else if (dtype == DISP_NOT_FCC_OR_HCP) {
268 epicenter = cnaEpiCenter(&initial, cutoff);
269 } else {
270 return false;
271 }
272
273 target = initial;
274 const long n = initial.numberOfAtoms();
275 const double radius = opt.displace_radius;
276 const double mag = opt.displace_magnitude;
277 AtomMatrix pos = initial.getPositionsCopy();
278 AtomMatrix mode = AtomMatrix::Zero(n, 3);
279 for (long i = 0; i < n; ++i) {
280 if (initial.getFixed(i)) {
281 continue;
282 }
283 const double dist = (i == epicenter) ? 0.0 : initial.distance(epicenter, i);
284 if (dist <= radius) {
285 for (int a = 0; a < 3; ++a) {
286 mode(i, a) = eonc::rng::gaussRandom(0.0, mag);
287 }
288 }
289 }
290 const double norm = mode.norm();
291 if (norm > 0.0) {
292 pos += mode;
293 mode /= norm;
294 } else if (epicenter >= 0 && epicenter < n && !initial.getFixed(epicenter)) {
295 mode(epicenter, 0) = 1.0;
296 pos(epicenter, 0) += mag;
297 }
298 target.setPositions(pos);
299 if (modeOut != nullptr) {
300 *modeOut = std::move(mode);
301 }
302 return true;
303}
304
305void eonc::helpers::saveMode(FILE *modeFile, std::shared_ptr<Matter> matter,
306 AtomMatrix mode) {
307 const AtomMatrix free = matter->getFree();
308 long const nAtoms = matter->numberOfAtoms();
309 for (long i = 0; i < nAtoms; ++i) {
310 fprintf(modeFile, "%.17g\t%.17g\t%.17g\n", free(i, 0) * mode(i, 0),
311 free(i, 1) * mode(i, 1), free(i, 2) * mode(i, 2));
312 }
313 return;
314}
315
316void eonc::helpers::saveMode(const std::string &filename,
317 std::shared_ptr<Matter> matter, AtomMatrix mode) {
318 std::ofstream out(filename);
319 if (!out)
320 return;
321 const AtomMatrix free = matter->getFree();
322 long const nAtoms = matter->numberOfAtoms();
323 for (long i = 0; i < nAtoms; ++i) {
324 out << std::format("{:.17g}\t{:.17g}\t{:.17g}\n", free(i, 0) * mode(i, 0),
325 free(i, 1) * mode(i, 1), free(i, 2) * mode(i, 2));
326 }
327}
328
329std::vector<int> eonc::helpers::split_string_int(std::string s,
330 std::string delim) {
331 std::vector<int> list;
332 if (s.empty())
333 return list;
334
335 size_t start = 0;
336 size_t end = s.find_first_of(delim);
337 while (start < s.size()) {
338 auto token = s.substr(start, end - start);
339 if (!token.empty()) {
340 try {
341 list.push_back(std::stoi(token));
342 } catch (const std::exception &) {
343 return {}; // Parse error
344 }
345 }
346 if (end == std::string::npos)
347 break;
348 start = end + 1;
349 end = s.find_first_of(delim, start);
350 }
351 return list;
352}
353
354std::optional<std::string_view>
356 if (metric == "max_atom") {
357 return "Max atom force";
358 }
359 if (metric == "max_component") {
360 return "Max force comp";
361 }
362 if (metric == "norm") {
363 return "||Force||";
364 }
365 if (metric == "rms") {
366 return "RMS force";
367 }
368 return std::nullopt;
369}
370
372 std::string_view context) {
373 if (convergenceMetricLabel(metric)) {
374 return;
375 }
376 throw std::invalid_argument(
377 std::format("{} unknown convergence_metric: {}", context, metric));
378}
379
380namespace {
381class MatterObjectiveFunction : public eonc::ObjectiveFunction {
382 eonc::Matter &m_matter; // non-owning reference, avoids copy
383public:
384 MatterObjectiveFunction(eonc::Matter &mat,
385 const eonc::Parameters &parametersPassed)
386 : eonc::ObjectiveFunction(parametersPassed),
387 m_matter{mat} {
389 params.optimizer_options().convergence_metric, "[Matter]");
390 }
391 ~MatterObjectiveFunction() = default;
392 double getEnergy() { return m_matter.getPotentialEnergy(); }
393 VectorXd getGradient(bool fdstep = false) {
394 return -m_matter.getForcesFreeV();
395 }
396 void setPositions(const VectorXd &x) { m_matter.setPositionsFreeV(x); }
397 VectorXd getPositions() { return m_matter.getPositionsFreeV(); }
398 int degreesOfFreedom() { return 3 * m_matter.numberOfFreeAtoms(); }
399 bool isConverged() {
400 return getConvergence() < params.optimizer_options().converged_force;
401 }
402 double getConvergence() {
403 if (params.optimizer_options().convergence_metric == "norm") {
404 return m_matter.getForcesFreeV().norm();
405 } else if (params.optimizer_options().convergence_metric == "rms") {
406 const VectorXd f = m_matter.getForcesFreeV();
407 const auto n = f.size();
408 return n > 0 ? f.norm() / std::sqrt(static_cast<double>(n)) : 0.0;
409 } else if (params.optimizer_options().convergence_metric == "max_atom") {
410 return m_matter.maxForce();
411 } else if (params.optimizer_options().convergence_metric ==
412 "max_component") {
413 return m_matter.getForces().cwiseAbs().maxCoeff();
414 } else {
415 EONC_LOG_CRITICAL("{} Unknown opt_convergence_metric: {}", "[Matter]",
416 params.optimizer_options().convergence_metric);
417 throw std::invalid_argument(
418 std::format("[Matter] unknown convergence_metric: {}",
419 params.optimizer_options().convergence_metric));
420 }
421 }
422 VectorXd difference(const VectorXd &a, const VectorXd &b) {
423 return m_matter.pbcV(a - b);
424 }
425 VectorXd getMasses() const override {
426 const auto all = m_matter.getMasses();
427 const auto mask = m_matter.getFree();
428 VectorXd out(m_matter.numberOfFreeAtoms());
429 long k = 0;
430 for (long i = 0; i < m_matter.numberOfAtoms(); ++i) {
431 if (mask.row(i).sum() > 0.5) {
432 out[k++] = all[i];
433 }
434 }
435 return out;
436 }
437 bool getPeriodic() const override { return m_matter.getPeriodic(); }
438 void minimumImage(Eigen::Ref<Eigen::Vector3d> dr) const override {
439 AtomMatrix m(1, 3);
440 m.row(0) = dr.transpose();
441 m = m_matter.pbc(m);
442 dr = m.row(0).transpose();
443 }
444};
445} // namespace
446
447bool eonc::helpers::relaxMatter(Matter &matter, const Parameters &params,
448 bool quiet, bool writeMovie, bool checkpoint,
449 std::string prefixMovie,
450 std::string prefixCheckpoint,
451 std::vector<readcon::ConFrame> *outFrames) {
452 eonc::log::Scoped m_log;
453 auto objf = std::make_shared<MatterObjectiveFunction>(matter, params);
455 objf, params.optimizer_options().method, params);
456
457 std::ostringstream min;
458 min << prefixMovie;
459 std::string minDatFilename = prefixMovie + ".dat";
460 auto write_movie_frame = [&](uint64_t frameIndex, bool append,
461 double stepSize) {
463 metadata.frame_index = frameIndex;
464 metadata.energy = matter.getPotentialEnergy();
465 metadata.scalars.push_back({"step_size", stepSize});
466 metadata.scalars.push_back({"convergence", objf->getConvergence()});
467 if (outFrames) {
468 outFrames->push_back(eonc::io::matterToConFrame(matter, &metadata));
469 }
470 if (writeMovie) {
471 if (!eonc::io::io_ok(matter.matter2con(min.str(), append, &metadata))) {
472 QUILL_LOG_WARNING(m_log, "Failed to write movie frame {}", min.str());
473 }
474 }
475
477 std::ofstream minDat(minDatFilename,
478 append ? (std::ios::binary | std::ios::app)
479 : std::ios::binary);
480 if (minDat) {
481 if (!append) {
482 minDat << "iteration\tstep_size\tconvergence\tenergy\n";
483 }
484 minDat << std::format("{}\t{:.5e}\t{:.5e}\t{:.6f}\n", frameIndex,
485 stepSize, objf->getConvergence(),
486 matter.getPotentialEnergy());
487 }
488 }
489 };
490 if (writeMovie || outFrames) {
491 write_movie_frame(0, false, 0.0);
492 }
493
494 int iteration = 0;
495 if (!quiet) {
496 QUILL_LOG_DEBUG(m_log, "{} {:10s} {:14s} {:18s} {:13s}\n", "[Matter]",
497 "Iter", "Step size",
499 "Energy");
500 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}\n",
501 "[Matter]", iteration, 0.0, objf->getConvergence(),
502 matter.getPotentialEnergy());
503 }
504
505 while (!objf->isConverged() &&
506 iteration < params.optimizer_options().max_iterations) {
507
508 AtomMatrix pos = matter.getPositions();
509
510 optim->step(params.optimizer_options().max_move);
511 iteration++;
512
513 double stepSize =
514 eonc::geometry::maxAtomMotion(matter.pbc(matter.getPositions() - pos));
515
516 if (!quiet) {
517 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}",
518 "[Matter]", iteration, stepSize, objf->getConvergence(),
519 matter.getPotentialEnergy());
520 }
521
522 if (writeMovie || outFrames) {
523 write_movie_frame(static_cast<uint64_t>(iteration), true, stepSize);
524 }
525
526 if (checkpoint) {
527 std::ostringstream chk;
528 chk << prefixCheckpoint << "_cp";
529 if (!eonc::io::io_ok(matter.matter2con(chk.str(), false))) {
530 QUILL_LOG_WARNING(m_log, "Failed to write checkpoint {}", chk.str());
531 }
532 }
533 }
534
535 if (iteration == 0) {
536 if (!quiet) {
537 QUILL_LOG_DEBUG(m_log, "{} {:10} {:14.5e} {:18.5e} {:13.5f}",
538 "[Matter]", iteration, 0.0, objf->getConvergence(),
539 matter.getPotentialEnergy());
540 }
541 }
542 return objf->isConverged();
543}
double matDot(const AtomMatrix &a, const AtomMatrix &b)
SIMD-optimized dot product for contiguous Eigen matrices.
Definition Eigen.h:50
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:261
#define EONC_LOG_WARNING(...)
Definition EonLogger.h:255
#define EONC_LOG_INFO(...)
Definition EonLogger.h:249
#define EONC_LOG_CRITICAL(...)
Definition EonLogger.h:267
The optimizer class is used to serve as an abstract class for all optimizers, as well as to call an o...
const AtomMatrix & getPositions() const
Definition Matter.cpp:308
VectorXd getForcesFreeV() const
Definition Matter.cpp:442
void setPositions(const AtomMatrix &pos)
Definition Matter.cpp:350
AtomMatrix getFree() const
Definition Matter.cpp:704
bool getPeriodic() const noexcept
Definition Matter.h:313
void setPositionsFreeV(const VectorXd &pos)
Definition Matter.cpp:381
long int numberOfAtoms() const
Definition Matter.cpp:273
AtomMatrix pbc(const AtomMatrix &diff) const
Definition Matter.cpp:810
VectorXd getPositionsFreeV() const
Definition Matter.cpp:345
void setAtomIndex(long int atom, std::int64_t index)
Definition Matter.cpp:830
VectorXd pbcV(const VectorXd &diff) const
Definition Matter.cpp:817
Eigen::Matrix< double, Eigen::Dynamic, 1 > getMasses() const
Definition Matter.cpp:750
double distance(long index1, long index2) const
Definition Matter.cpp:448
double getPotentialEnergy() const
Definition Matter.cpp:554
long mapFileRow(long file_row) const
Map a CON file-order row onto the Matter row after matter_order.
Definition Matter.h:293
long int numberOfFreeAtoms() const
Definition Matter.cpp:583
AtomMatrix getPositionsCopy() const
Definition Matter.cpp:310
std::int64_t getAtomIndex(long int atom) const
.con column-5 index (pre-grouping); public for I/O / bindings.
Definition Matter.cpp:826
const AtomMatrix & getForces() const
Definition Matter.cpp:412
void setFileToMatter(std::vector< long > map)
Definition Matter.h:300
io::IoStatus matter2con(std::string filename, bool append=false, const io::ConFrameMetadata *metadata=nullptr)
Definition Matter.h:268
int getFixed(long int atom) const
1 if every Cartesian axis of the atom is fixed, else 0.
Definition Matter.cpp:505
io::IoStatus con2matter(std::string filename)
Definition Matter.h:256
double maxForce(void) const
Definition Matter.cpp:685
const saddle_search_options_t & saddle_search_options() const
const debug_options_t & debug_options() const
const structure_comparison_options_t & structure_comparison_options() const
const optimizer_options_t & optimizer_options() const
const char DISP_RANDOM[]
Definition EpiCenters.h:24
long lastAtom(const Matter *matter)
const char DISP_LISTED_ATOMS[]
Definition EpiCenters.h:25
const char DISP_NOT_FCC_OR_HCP[]
Definition EpiCenters.h:21
const char DISP_MIN_COORDINATED[]
Definition EpiCenters.h:22
long cnaEpiCenter(const Matter *matter, double neighborCutoff)
const char DISP_LOAD[]
Definition EpiCenters.h:20
const char DISP_LAST_ATOM[]
Definition EpiCenters.h:23
long randomFreeAtomEpiCenter(const Matter *matter)
long listedAtomEpiCenter(const Matter *matter, const std::vector< long > &atomList)
long minCoordinatedEpiCenter(const Matter *matter, double neighborCutoff)
double maxAtomMotion(const AtomMatrix v1)
std::unique_ptr< Optimizer > mkOptim(std::shared_ptr< ObjectiveFunction > a_objf, OptType a_otype, const Parameters &a_params)
Definition Optimizer.cpp:24
VectorXd loadMasses(std::string filename, int nAtoms)
bool applyClientDisplacement(Matter &target, const Matter &initial, const Parameters &params, AtomMatrix *modeOut)
bool relaxMatter(Matter &matter, const Parameters &params, bool quiet=false, bool writeMovie=false, bool checkpoint=false, std::string prefixMovie=std::string(), std::string prefixCheckpoint=std::string(), std::vector< readcon::ConFrame > *outFrames=nullptr)
std::string getRelevantFile(std::string filename)
bool loadOrSynthesizeDisplacement(Matter &target, const Matter &initial, const std::string &displacementPath, const std::string &modePath, double scale)
AtomMatrix loadMode(FILE *modeFile, int nAtoms)
void saveMode(FILE *modeFile, std::shared_ptr< Matter > matter, AtomMatrix mode)
Write a mode; constrained axes are emitted as 0.
std::optional< std::string_view > convergenceMetricLabel(std::string_view metric)
Display label for a force-convergence metric, or nullopt when the name is none of the four the optimi...
std::vector< int > split_string_int(std::string s, std::string delim)
bool stageReturnLog(std::string_view logHome, std::string_view name)
Copy name from logHome into the current directory when that file is not already this directory's copy...
void requireKnownConvergenceMetric(std::string_view metric, std::string_view context)
Throws std::invalid_argument naming context when metric is unrecognized.
std::optional< std::string > enterJobDirectory(std::string_view jobPath)
Enter jobPath as the working directory.
void getTime(double *real, double *user, double *sys)
AtomMatrix makeOrthogonal(const AtomMatrix v1, const AtomMatrix v2)
bool existsFile(std::string filename)
readcon::ConFrame matterToConFrame(Matter &m, const ConFrameMetadata *metadata)
Build a single stamped ConFrame from Matter (same builder as matter2con).
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38
double gaussRandom(double avg, double std)
RAII resource manager for the ARTn C library with global synchronization.
std::optional< uint64_t > frame_index
Definition ConFileIO.h:72
std::vector< ConMetadataValue > scalars
Definition ConFileIO.h:79
std::optional< double > energy
Definition ConFileIO.h:73
RAII helper for class-scoped logging.
Definition EonLogger.h:171